intl/icu/source/i18n/decimfmt.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 *******************************************************************************
michael@0 3 * Copyright (C) 1997-2013, International Business Machines Corporation and *
michael@0 4 * others. All Rights Reserved. *
michael@0 5 *******************************************************************************
michael@0 6 *
michael@0 7 * File DECIMFMT.CPP
michael@0 8 *
michael@0 9 * Modification History:
michael@0 10 *
michael@0 11 * Date Name Description
michael@0 12 * 02/19/97 aliu Converted from java.
michael@0 13 * 03/20/97 clhuang Implemented with new APIs.
michael@0 14 * 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it.
michael@0 15 * 04/3/97 aliu Rewrote parsing and formatting completely, and
michael@0 16 * cleaned up and debugged. Actually works now.
michael@0 17 * Implemented NAN and INF handling, for both parsing
michael@0 18 * and formatting. Extensive testing & debugging.
michael@0 19 * 04/10/97 aliu Modified to compile on AIX.
michael@0 20 * 04/16/97 aliu Rewrote to use DigitList, which has been resurrected.
michael@0 21 * Changed DigitCount to int per code review.
michael@0 22 * 07/09/97 helena Made ParsePosition into a class.
michael@0 23 * 08/26/97 aliu Extensive changes to applyPattern; completely
michael@0 24 * rewritten from the Java.
michael@0 25 * 09/09/97 aliu Ported over support for exponential formats.
michael@0 26 * 07/20/98 stephen JDK 1.2 sync up.
michael@0 27 * Various instances of '0' replaced with 'NULL'
michael@0 28 * Check for grouping size in subFormat()
michael@0 29 * Brought subParse() in line with Java 1.2
michael@0 30 * Added method appendAffix()
michael@0 31 * 08/24/1998 srl Removed Mutex calls. This is not a thread safe class!
michael@0 32 * 02/22/99 stephen Removed character literals for EBCDIC safety
michael@0 33 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes
michael@0 34 * 06/28/99 stephen Fixed bugs in toPattern().
michael@0 35 * 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad,
michael@0 36 * fPadPosition
michael@0 37 ********************************************************************************
michael@0 38 */
michael@0 39
michael@0 40 #include "unicode/utypes.h"
michael@0 41
michael@0 42 #if !UCONFIG_NO_FORMATTING
michael@0 43
michael@0 44 #include "fphdlimp.h"
michael@0 45 #include "unicode/decimfmt.h"
michael@0 46 #include "unicode/choicfmt.h"
michael@0 47 #include "unicode/ucurr.h"
michael@0 48 #include "unicode/ustring.h"
michael@0 49 #include "unicode/dcfmtsym.h"
michael@0 50 #include "unicode/ures.h"
michael@0 51 #include "unicode/uchar.h"
michael@0 52 #include "unicode/uniset.h"
michael@0 53 #include "unicode/curramt.h"
michael@0 54 #include "unicode/currpinf.h"
michael@0 55 #include "unicode/plurrule.h"
michael@0 56 #include "unicode/utf16.h"
michael@0 57 #include "unicode/numsys.h"
michael@0 58 #include "unicode/localpointer.h"
michael@0 59 #include "uresimp.h"
michael@0 60 #include "ucurrimp.h"
michael@0 61 #include "charstr.h"
michael@0 62 #include "cmemory.h"
michael@0 63 #include "patternprops.h"
michael@0 64 #include "digitlst.h"
michael@0 65 #include "cstring.h"
michael@0 66 #include "umutex.h"
michael@0 67 #include "uassert.h"
michael@0 68 #include "putilimp.h"
michael@0 69 #include <math.h>
michael@0 70 #include "hash.h"
michael@0 71 #include "decfmtst.h"
michael@0 72 #include "dcfmtimp.h"
michael@0 73 #include "plurrule_impl.h"
michael@0 74
michael@0 75 /*
michael@0 76 * On certain platforms, round is a macro defined in math.h
michael@0 77 * This undefine is to avoid conflict between the macro and
michael@0 78 * the function defined below.
michael@0 79 */
michael@0 80 #ifdef round
michael@0 81 #undef round
michael@0 82 #endif
michael@0 83
michael@0 84
michael@0 85 U_NAMESPACE_BEGIN
michael@0 86
michael@0 87 #ifdef FMT_DEBUG
michael@0 88 #include <stdio.h>
michael@0 89 static void _debugout(const char *f, int l, const UnicodeString& s) {
michael@0 90 char buf[2000];
michael@0 91 s.extract((int32_t) 0, s.length(), buf, "utf-8");
michael@0 92 printf("%s:%d: %s\n", f,l, buf);
michael@0 93 }
michael@0 94 #define debugout(x) _debugout(__FILE__,__LINE__,x)
michael@0 95 #define debug(x) printf("%s:%d: %s\n", __FILE__,__LINE__, x);
michael@0 96 static const UnicodeString dbg_null("<NULL>","");
michael@0 97 #define DEREFSTR(x) ((x!=NULL)?(*x):(dbg_null))
michael@0 98 #else
michael@0 99 #define debugout(x)
michael@0 100 #define debug(x)
michael@0 101 #endif
michael@0 102
michael@0 103
michael@0 104
michael@0 105 /* == Fastpath calculation. ==
michael@0 106 */
michael@0 107 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 108 inline DecimalFormatInternal& internalData(uint8_t *reserved) {
michael@0 109 return *reinterpret_cast<DecimalFormatInternal*>(reserved);
michael@0 110 }
michael@0 111 inline const DecimalFormatInternal& internalData(const uint8_t *reserved) {
michael@0 112 return *reinterpret_cast<const DecimalFormatInternal*>(reserved);
michael@0 113 }
michael@0 114 #else
michael@0 115 #endif
michael@0 116
michael@0 117 /* For currency parsing purose,
michael@0 118 * Need to remember all prefix patterns and suffix patterns of
michael@0 119 * every currency format pattern,
michael@0 120 * including the pattern of default currecny style
michael@0 121 * and plural currency style. And the patterns are set through applyPattern.
michael@0 122 */
michael@0 123 struct AffixPatternsForCurrency : public UMemory {
michael@0 124 // negative prefix pattern
michael@0 125 UnicodeString negPrefixPatternForCurrency;
michael@0 126 // negative suffix pattern
michael@0 127 UnicodeString negSuffixPatternForCurrency;
michael@0 128 // positive prefix pattern
michael@0 129 UnicodeString posPrefixPatternForCurrency;
michael@0 130 // positive suffix pattern
michael@0 131 UnicodeString posSuffixPatternForCurrency;
michael@0 132 int8_t patternType;
michael@0 133
michael@0 134 AffixPatternsForCurrency(const UnicodeString& negPrefix,
michael@0 135 const UnicodeString& negSuffix,
michael@0 136 const UnicodeString& posPrefix,
michael@0 137 const UnicodeString& posSuffix,
michael@0 138 int8_t type) {
michael@0 139 negPrefixPatternForCurrency = negPrefix;
michael@0 140 negSuffixPatternForCurrency = negSuffix;
michael@0 141 posPrefixPatternForCurrency = posPrefix;
michael@0 142 posSuffixPatternForCurrency = posSuffix;
michael@0 143 patternType = type;
michael@0 144 }
michael@0 145 #ifdef FMT_DEBUG
michael@0 146 void dump() const {
michael@0 147 debugout( UnicodeString("AffixPatternsForCurrency( -=\"") +
michael@0 148 negPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
michael@0 149 negSuffixPatternForCurrency + (UnicodeString)"\" +=\"" +
michael@0 150 posPrefixPatternForCurrency + (UnicodeString)"\"/\"" +
michael@0 151 posSuffixPatternForCurrency + (UnicodeString)"\" )");
michael@0 152 }
michael@0 153 #endif
michael@0 154 };
michael@0 155
michael@0 156 /* affix for currency formatting when the currency sign in the pattern
michael@0 157 * equals to 3, such as the pattern contains 3 currency sign or
michael@0 158 * the formatter style is currency plural format style.
michael@0 159 */
michael@0 160 struct AffixesForCurrency : public UMemory {
michael@0 161 // negative prefix
michael@0 162 UnicodeString negPrefixForCurrency;
michael@0 163 // negative suffix
michael@0 164 UnicodeString negSuffixForCurrency;
michael@0 165 // positive prefix
michael@0 166 UnicodeString posPrefixForCurrency;
michael@0 167 // positive suffix
michael@0 168 UnicodeString posSuffixForCurrency;
michael@0 169
michael@0 170 int32_t formatWidth;
michael@0 171
michael@0 172 AffixesForCurrency(const UnicodeString& negPrefix,
michael@0 173 const UnicodeString& negSuffix,
michael@0 174 const UnicodeString& posPrefix,
michael@0 175 const UnicodeString& posSuffix) {
michael@0 176 negPrefixForCurrency = negPrefix;
michael@0 177 negSuffixForCurrency = negSuffix;
michael@0 178 posPrefixForCurrency = posPrefix;
michael@0 179 posSuffixForCurrency = posSuffix;
michael@0 180 }
michael@0 181 #ifdef FMT_DEBUG
michael@0 182 void dump() const {
michael@0 183 debugout( UnicodeString("AffixesForCurrency( -=\"") +
michael@0 184 negPrefixForCurrency + (UnicodeString)"\"/\"" +
michael@0 185 negSuffixForCurrency + (UnicodeString)"\" +=\"" +
michael@0 186 posPrefixForCurrency + (UnicodeString)"\"/\"" +
michael@0 187 posSuffixForCurrency + (UnicodeString)"\" )");
michael@0 188 }
michael@0 189 #endif
michael@0 190 };
michael@0 191
michael@0 192 U_CDECL_BEGIN
michael@0 193
michael@0 194 /**
michael@0 195 * @internal ICU 4.2
michael@0 196 */
michael@0 197 static UBool U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2);
michael@0 198
michael@0 199 /**
michael@0 200 * @internal ICU 4.2
michael@0 201 */
michael@0 202 static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2);
michael@0 203
michael@0 204
michael@0 205 static UBool
michael@0 206 U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2) {
michael@0 207 const AffixesForCurrency* affix_1 =
michael@0 208 (AffixesForCurrency*)val1.pointer;
michael@0 209 const AffixesForCurrency* affix_2 =
michael@0 210 (AffixesForCurrency*)val2.pointer;
michael@0 211 return affix_1->negPrefixForCurrency == affix_2->negPrefixForCurrency &&
michael@0 212 affix_1->negSuffixForCurrency == affix_2->negSuffixForCurrency &&
michael@0 213 affix_1->posPrefixForCurrency == affix_2->posPrefixForCurrency &&
michael@0 214 affix_1->posSuffixForCurrency == affix_2->posSuffixForCurrency;
michael@0 215 }
michael@0 216
michael@0 217
michael@0 218 static UBool
michael@0 219 U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) {
michael@0 220 const AffixPatternsForCurrency* affix_1 =
michael@0 221 (AffixPatternsForCurrency*)val1.pointer;
michael@0 222 const AffixPatternsForCurrency* affix_2 =
michael@0 223 (AffixPatternsForCurrency*)val2.pointer;
michael@0 224 return affix_1->negPrefixPatternForCurrency ==
michael@0 225 affix_2->negPrefixPatternForCurrency &&
michael@0 226 affix_1->negSuffixPatternForCurrency ==
michael@0 227 affix_2->negSuffixPatternForCurrency &&
michael@0 228 affix_1->posPrefixPatternForCurrency ==
michael@0 229 affix_2->posPrefixPatternForCurrency &&
michael@0 230 affix_1->posSuffixPatternForCurrency ==
michael@0 231 affix_2->posSuffixPatternForCurrency &&
michael@0 232 affix_1->patternType == affix_2->patternType;
michael@0 233 }
michael@0 234
michael@0 235 U_CDECL_END
michael@0 236
michael@0 237
michael@0 238
michael@0 239
michael@0 240 // *****************************************************************************
michael@0 241 // class DecimalFormat
michael@0 242 // *****************************************************************************
michael@0 243
michael@0 244 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
michael@0 245
michael@0 246 // Constants for characters used in programmatic (unlocalized) patterns.
michael@0 247 #define kPatternZeroDigit ((UChar)0x0030) /*'0'*/
michael@0 248 #define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/
michael@0 249 #define kPatternGroupingSeparator ((UChar)0x002C) /*','*/
michael@0 250 #define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/
michael@0 251 #define kPatternPerMill ((UChar)0x2030)
michael@0 252 #define kPatternPercent ((UChar)0x0025) /*'%'*/
michael@0 253 #define kPatternDigit ((UChar)0x0023) /*'#'*/
michael@0 254 #define kPatternSeparator ((UChar)0x003B) /*';'*/
michael@0 255 #define kPatternExponent ((UChar)0x0045) /*'E'*/
michael@0 256 #define kPatternPlus ((UChar)0x002B) /*'+'*/
michael@0 257 #define kPatternMinus ((UChar)0x002D) /*'-'*/
michael@0 258 #define kPatternPadEscape ((UChar)0x002A) /*'*'*/
michael@0 259 #define kQuote ((UChar)0x0027) /*'\''*/
michael@0 260 /**
michael@0 261 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
michael@0 262 * is used in patterns and substitued with either the currency symbol,
michael@0 263 * or if it is doubled, with the international currency symbol. If the
michael@0 264 * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
michael@0 265 * replaced with the monetary decimal separator.
michael@0 266 */
michael@0 267 #define kCurrencySign ((UChar)0x00A4)
michael@0 268 #define kDefaultPad ((UChar)0x0020) /* */
michael@0 269
michael@0 270 const int32_t DecimalFormat::kDoubleIntegerDigits = 309;
michael@0 271 const int32_t DecimalFormat::kDoubleFractionDigits = 340;
michael@0 272
michael@0 273 const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8;
michael@0 274
michael@0 275 /**
michael@0 276 * These are the tags we expect to see in normal resource bundle files associated
michael@0 277 * with a locale.
michael@0 278 */
michael@0 279 const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - not used
michael@0 280 static const char fgNumberElements[]="NumberElements";
michael@0 281 static const char fgLatn[]="latn";
michael@0 282 static const char fgPatterns[]="patterns";
michael@0 283 static const char fgDecimalFormat[]="decimalFormat";
michael@0 284 static const char fgCurrencyFormat[]="currencyFormat";
michael@0 285
michael@0 286 static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0};
michael@0 287
michael@0 288 inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; }
michael@0 289 inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; }
michael@0 290
michael@0 291 //------------------------------------------------------------------------------
michael@0 292 // Constructs a DecimalFormat instance in the default locale.
michael@0 293
michael@0 294 DecimalFormat::DecimalFormat(UErrorCode& status) {
michael@0 295 init();
michael@0 296 UParseError parseError;
michael@0 297 construct(status, parseError);
michael@0 298 }
michael@0 299
michael@0 300 //------------------------------------------------------------------------------
michael@0 301 // Constructs a DecimalFormat instance with the specified number format
michael@0 302 // pattern in the default locale.
michael@0 303
michael@0 304 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
michael@0 305 UErrorCode& status) {
michael@0 306 init();
michael@0 307 UParseError parseError;
michael@0 308 construct(status, parseError, &pattern);
michael@0 309 }
michael@0 310
michael@0 311 //------------------------------------------------------------------------------
michael@0 312 // Constructs a DecimalFormat instance with the specified number format
michael@0 313 // pattern and the number format symbols in the default locale. The
michael@0 314 // created instance owns the symbols.
michael@0 315
michael@0 316 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
michael@0 317 DecimalFormatSymbols* symbolsToAdopt,
michael@0 318 UErrorCode& status) {
michael@0 319 init();
michael@0 320 UParseError parseError;
michael@0 321 if (symbolsToAdopt == NULL)
michael@0 322 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 323 construct(status, parseError, &pattern, symbolsToAdopt);
michael@0 324 }
michael@0 325
michael@0 326 DecimalFormat::DecimalFormat( const UnicodeString& pattern,
michael@0 327 DecimalFormatSymbols* symbolsToAdopt,
michael@0 328 UParseError& parseErr,
michael@0 329 UErrorCode& status) {
michael@0 330 init();
michael@0 331 if (symbolsToAdopt == NULL)
michael@0 332 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 333 construct(status,parseErr, &pattern, symbolsToAdopt);
michael@0 334 }
michael@0 335
michael@0 336 //------------------------------------------------------------------------------
michael@0 337 // Constructs a DecimalFormat instance with the specified number format
michael@0 338 // pattern and the number format symbols in the default locale. The
michael@0 339 // created instance owns the clone of the symbols.
michael@0 340
michael@0 341 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
michael@0 342 const DecimalFormatSymbols& symbols,
michael@0 343 UErrorCode& status) {
michael@0 344 init();
michael@0 345 UParseError parseError;
michael@0 346 construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
michael@0 347 }
michael@0 348
michael@0 349 //------------------------------------------------------------------------------
michael@0 350 // Constructs a DecimalFormat instance with the specified number format
michael@0 351 // pattern, the number format symbols, and the number format style.
michael@0 352 // The created instance owns the clone of the symbols.
michael@0 353
michael@0 354 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
michael@0 355 DecimalFormatSymbols* symbolsToAdopt,
michael@0 356 UNumberFormatStyle style,
michael@0 357 UErrorCode& status) {
michael@0 358 init();
michael@0 359 fStyle = style;
michael@0 360 UParseError parseError;
michael@0 361 construct(status, parseError, &pattern, symbolsToAdopt);
michael@0 362 }
michael@0 363
michael@0 364 //-----------------------------------------------------------------------------
michael@0 365 // Common DecimalFormat initialization.
michael@0 366 // Put all fields of an uninitialized object into a known state.
michael@0 367 // Common code, shared by all constructors.
michael@0 368 // Can not fail. Leave the object in good enough shape that the destructor
michael@0 369 // or assignment operator can run successfully.
michael@0 370 void
michael@0 371 DecimalFormat::init() {
michael@0 372 fPosPrefixPattern = 0;
michael@0 373 fPosSuffixPattern = 0;
michael@0 374 fNegPrefixPattern = 0;
michael@0 375 fNegSuffixPattern = 0;
michael@0 376 fCurrencyChoice = 0;
michael@0 377 fMultiplier = NULL;
michael@0 378 fScale = 0;
michael@0 379 fGroupingSize = 0;
michael@0 380 fGroupingSize2 = 0;
michael@0 381 fDecimalSeparatorAlwaysShown = FALSE;
michael@0 382 fSymbols = NULL;
michael@0 383 fUseSignificantDigits = FALSE;
michael@0 384 fMinSignificantDigits = 1;
michael@0 385 fMaxSignificantDigits = 6;
michael@0 386 fUseExponentialNotation = FALSE;
michael@0 387 fMinExponentDigits = 0;
michael@0 388 fExponentSignAlwaysShown = FALSE;
michael@0 389 fBoolFlags.clear();
michael@0 390 fRoundingIncrement = 0;
michael@0 391 fRoundingMode = kRoundHalfEven;
michael@0 392 fPad = 0;
michael@0 393 fFormatWidth = 0;
michael@0 394 fPadPosition = kPadBeforePrefix;
michael@0 395 fStyle = UNUM_DECIMAL;
michael@0 396 fCurrencySignCount = fgCurrencySignCountZero;
michael@0 397 fAffixPatternsForCurrency = NULL;
michael@0 398 fAffixesForCurrency = NULL;
michael@0 399 fPluralAffixesForCurrency = NULL;
michael@0 400 fCurrencyPluralInfo = NULL;
michael@0 401 #if UCONFIG_HAVE_PARSEALLINPUT
michael@0 402 fParseAllInput = UNUM_MAYBE;
michael@0 403 #endif
michael@0 404
michael@0 405 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 406 DecimalFormatInternal &data = internalData(fReserved);
michael@0 407 data.fFastFormatStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
michael@0 408 data.fFastParseStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
michael@0 409 #endif
michael@0 410 fStaticSets = NULL;
michael@0 411 }
michael@0 412
michael@0 413 //------------------------------------------------------------------------------
michael@0 414 // Constructs a DecimalFormat instance with the specified number format
michael@0 415 // pattern and the number format symbols in the desired locale. The
michael@0 416 // created instance owns the symbols.
michael@0 417
michael@0 418 void
michael@0 419 DecimalFormat::construct(UErrorCode& status,
michael@0 420 UParseError& parseErr,
michael@0 421 const UnicodeString* pattern,
michael@0 422 DecimalFormatSymbols* symbolsToAdopt)
michael@0 423 {
michael@0 424 fSymbols = symbolsToAdopt; // Do this BEFORE aborting on status failure!!!
michael@0 425 fRoundingIncrement = NULL;
michael@0 426 fRoundingMode = kRoundHalfEven;
michael@0 427 fPad = kPatternPadEscape;
michael@0 428 fPadPosition = kPadBeforePrefix;
michael@0 429 if (U_FAILURE(status))
michael@0 430 return;
michael@0 431
michael@0 432 fPosPrefixPattern = fPosSuffixPattern = NULL;
michael@0 433 fNegPrefixPattern = fNegSuffixPattern = NULL;
michael@0 434 setMultiplier(1);
michael@0 435 fGroupingSize = 3;
michael@0 436 fGroupingSize2 = 0;
michael@0 437 fDecimalSeparatorAlwaysShown = FALSE;
michael@0 438 fUseExponentialNotation = FALSE;
michael@0 439 fMinExponentDigits = 0;
michael@0 440
michael@0 441 if (fSymbols == NULL)
michael@0 442 {
michael@0 443 fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status);
michael@0 444 if (fSymbols == 0) {
michael@0 445 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 446 return;
michael@0 447 }
michael@0 448 }
michael@0 449 fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
michael@0 450 if (U_FAILURE(status)) {
michael@0 451 return;
michael@0 452 }
michael@0 453 UErrorCode nsStatus = U_ZERO_ERROR;
michael@0 454 NumberingSystem *ns = NumberingSystem::createInstance(nsStatus);
michael@0 455 if (U_FAILURE(nsStatus)) {
michael@0 456 status = nsStatus;
michael@0 457 return;
michael@0 458 }
michael@0 459
michael@0 460 UnicodeString str;
michael@0 461 // Uses the default locale's number format pattern if there isn't
michael@0 462 // one specified.
michael@0 463 if (pattern == NULL)
michael@0 464 {
michael@0 465 int32_t len = 0;
michael@0 466 UResourceBundle *top = ures_open(NULL, Locale::getDefault().getName(), &status);
michael@0 467
michael@0 468 UResourceBundle *resource = ures_getByKeyWithFallback(top, fgNumberElements, NULL, &status);
michael@0 469 resource = ures_getByKeyWithFallback(resource, ns->getName(), resource, &status);
michael@0 470 resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
michael@0 471 const UChar *resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status);
michael@0 472 if ( status == U_MISSING_RESOURCE_ERROR && uprv_strcmp(fgLatn,ns->getName())) {
michael@0 473 status = U_ZERO_ERROR;
michael@0 474 resource = ures_getByKeyWithFallback(top, fgNumberElements, resource, &status);
michael@0 475 resource = ures_getByKeyWithFallback(resource, fgLatn, resource, &status);
michael@0 476 resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &status);
michael@0 477 resStr = ures_getStringByKeyWithFallback(resource, fgDecimalFormat, &len, &status);
michael@0 478 }
michael@0 479 str.setTo(TRUE, resStr, len);
michael@0 480 pattern = &str;
michael@0 481 ures_close(resource);
michael@0 482 ures_close(top);
michael@0 483 }
michael@0 484
michael@0 485 delete ns;
michael@0 486
michael@0 487 if (U_FAILURE(status))
michael@0 488 {
michael@0 489 return;
michael@0 490 }
michael@0 491
michael@0 492 if (pattern->indexOf((UChar)kCurrencySign) >= 0) {
michael@0 493 // If it looks like we are going to use a currency pattern
michael@0 494 // then do the time consuming lookup.
michael@0 495 setCurrencyForSymbols();
michael@0 496 } else {
michael@0 497 setCurrencyInternally(NULL, status);
michael@0 498 }
michael@0 499
michael@0 500 const UnicodeString* patternUsed;
michael@0 501 UnicodeString currencyPluralPatternForOther;
michael@0 502 // apply pattern
michael@0 503 if (fStyle == UNUM_CURRENCY_PLURAL) {
michael@0 504 fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
michael@0 505 if (U_FAILURE(status)) {
michael@0 506 return;
michael@0 507 }
michael@0 508
michael@0 509 // the pattern used in format is not fixed until formatting,
michael@0 510 // in which, the number is known and
michael@0 511 // will be used to pick the right pattern based on plural count.
michael@0 512 // Here, set the pattern as the pattern of plural count == "other".
michael@0 513 // For most locale, the patterns are probably the same for all
michael@0 514 // plural count. If not, the right pattern need to be re-applied
michael@0 515 // during format.
michael@0 516 fCurrencyPluralInfo->getCurrencyPluralPattern(UNICODE_STRING("other", 5), currencyPluralPatternForOther);
michael@0 517 patternUsed = &currencyPluralPatternForOther;
michael@0 518 // TODO: not needed?
michael@0 519 setCurrencyForSymbols();
michael@0 520
michael@0 521 } else {
michael@0 522 patternUsed = pattern;
michael@0 523 }
michael@0 524
michael@0 525 if (patternUsed->indexOf(kCurrencySign) != -1) {
michael@0 526 // initialize for currency, not only for plural format,
michael@0 527 // but also for mix parsing
michael@0 528 if (fCurrencyPluralInfo == NULL) {
michael@0 529 fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
michael@0 530 if (U_FAILURE(status)) {
michael@0 531 return;
michael@0 532 }
michael@0 533 }
michael@0 534 // need it for mix parsing
michael@0 535 setupCurrencyAffixPatterns(status);
michael@0 536 // expanded affixes for plural names
michael@0 537 if (patternUsed->indexOf(fgTripleCurrencySign, 3, 0) != -1) {
michael@0 538 setupCurrencyAffixes(*patternUsed, TRUE, TRUE, status);
michael@0 539 }
michael@0 540 }
michael@0 541
michael@0 542 applyPatternWithoutExpandAffix(*patternUsed,FALSE, parseErr, status);
michael@0 543
michael@0 544 // expand affixes
michael@0 545 if (fCurrencySignCount != fgCurrencySignCountInPluralFormat) {
michael@0 546 expandAffixAdjustWidth(NULL);
michael@0 547 }
michael@0 548
michael@0 549 // If it was a currency format, apply the appropriate rounding by
michael@0 550 // resetting the currency. NOTE: this copies fCurrency on top of itself.
michael@0 551 if (fCurrencySignCount != fgCurrencySignCountZero) {
michael@0 552 setCurrencyInternally(getCurrency(), status);
michael@0 553 }
michael@0 554 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 555 DecimalFormatInternal &data = internalData(fReserved);
michael@0 556 data.fFastFormatStatus = kFastpathNO; // allow it to be calculated
michael@0 557 data.fFastParseStatus = kFastpathNO; // allow it to be calculated
michael@0 558 handleChanged();
michael@0 559 #endif
michael@0 560 }
michael@0 561
michael@0 562
michael@0 563 void
michael@0 564 DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) {
michael@0 565 if (U_FAILURE(status)) {
michael@0 566 return;
michael@0 567 }
michael@0 568 UParseError parseErr;
michael@0 569 fAffixPatternsForCurrency = initHashForAffixPattern(status);
michael@0 570 if (U_FAILURE(status)) {
michael@0 571 return;
michael@0 572 }
michael@0 573
michael@0 574 NumberingSystem *ns = NumberingSystem::createInstance(fSymbols->getLocale(),status);
michael@0 575 if (U_FAILURE(status)) {
michael@0 576 return;
michael@0 577 }
michael@0 578
michael@0 579 // Save the default currency patterns of this locale.
michael@0 580 // Here, chose onlyApplyPatternWithoutExpandAffix without
michael@0 581 // expanding the affix patterns into affixes.
michael@0 582 UnicodeString currencyPattern;
michael@0 583 UErrorCode error = U_ZERO_ERROR;
michael@0 584
michael@0 585 UResourceBundle *resource = ures_open(NULL, fSymbols->getLocale().getName(), &error);
michael@0 586 UResourceBundle *numElements = ures_getByKeyWithFallback(resource, fgNumberElements, NULL, &error);
michael@0 587 resource = ures_getByKeyWithFallback(numElements, ns->getName(), resource, &error);
michael@0 588 resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
michael@0 589 int32_t patLen = 0;
michael@0 590 const UChar *patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
michael@0 591 if ( error == U_MISSING_RESOURCE_ERROR && uprv_strcmp(ns->getName(),fgLatn)) {
michael@0 592 error = U_ZERO_ERROR;
michael@0 593 resource = ures_getByKeyWithFallback(numElements, fgLatn, resource, &error);
michael@0 594 resource = ures_getByKeyWithFallback(resource, fgPatterns, resource, &error);
michael@0 595 patResStr = ures_getStringByKeyWithFallback(resource, fgCurrencyFormat, &patLen, &error);
michael@0 596 }
michael@0 597 ures_close(numElements);
michael@0 598 ures_close(resource);
michael@0 599 delete ns;
michael@0 600
michael@0 601 if (U_SUCCESS(error)) {
michael@0 602 applyPatternWithoutExpandAffix(UnicodeString(patResStr, patLen), false,
michael@0 603 parseErr, status);
michael@0 604 AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
michael@0 605 *fNegPrefixPattern,
michael@0 606 *fNegSuffixPattern,
michael@0 607 *fPosPrefixPattern,
michael@0 608 *fPosSuffixPattern,
michael@0 609 UCURR_SYMBOL_NAME);
michael@0 610 fAffixPatternsForCurrency->put(UNICODE_STRING("default", 7), affixPtn, status);
michael@0 611 }
michael@0 612
michael@0 613 // save the unique currency plural patterns of this locale.
michael@0 614 Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPattern;
michael@0 615 const UHashElement* element = NULL;
michael@0 616 int32_t pos = -1;
michael@0 617 Hashtable pluralPatternSet;
michael@0 618 while ((element = pluralPtn->nextElement(pos)) != NULL) {
michael@0 619 const UHashTok valueTok = element->value;
michael@0 620 const UnicodeString* value = (UnicodeString*)valueTok.pointer;
michael@0 621 const UHashTok keyTok = element->key;
michael@0 622 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
michael@0 623 if (pluralPatternSet.geti(*value) != 1) {
michael@0 624 pluralPatternSet.puti(*value, 1, status);
michael@0 625 applyPatternWithoutExpandAffix(*value, false, parseErr, status);
michael@0 626 AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency(
michael@0 627 *fNegPrefixPattern,
michael@0 628 *fNegSuffixPattern,
michael@0 629 *fPosPrefixPattern,
michael@0 630 *fPosSuffixPattern,
michael@0 631 UCURR_LONG_NAME);
michael@0 632 fAffixPatternsForCurrency->put(*key, affixPtn, status);
michael@0 633 }
michael@0 634 }
michael@0 635 }
michael@0 636
michael@0 637
michael@0 638 void
michael@0 639 DecimalFormat::setupCurrencyAffixes(const UnicodeString& pattern,
michael@0 640 UBool setupForCurrentPattern,
michael@0 641 UBool setupForPluralPattern,
michael@0 642 UErrorCode& status) {
michael@0 643 if (U_FAILURE(status)) {
michael@0 644 return;
michael@0 645 }
michael@0 646 UParseError parseErr;
michael@0 647 if (setupForCurrentPattern) {
michael@0 648 if (fAffixesForCurrency) {
michael@0 649 deleteHashForAffix(fAffixesForCurrency);
michael@0 650 }
michael@0 651 fAffixesForCurrency = initHashForAffix(status);
michael@0 652 if (U_SUCCESS(status)) {
michael@0 653 applyPatternWithoutExpandAffix(pattern, false, parseErr, status);
michael@0 654 const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules();
michael@0 655 StringEnumeration* keywords = pluralRules->getKeywords(status);
michael@0 656 if (U_SUCCESS(status)) {
michael@0 657 const UnicodeString* pluralCount;
michael@0 658 while ((pluralCount = keywords->snext(status)) != NULL) {
michael@0 659 if ( U_SUCCESS(status) ) {
michael@0 660 expandAffixAdjustWidth(pluralCount);
michael@0 661 AffixesForCurrency* affix = new AffixesForCurrency(
michael@0 662 fNegativePrefix, fNegativeSuffix, fPositivePrefix, fPositiveSuffix);
michael@0 663 fAffixesForCurrency->put(*pluralCount, affix, status);
michael@0 664 }
michael@0 665 }
michael@0 666 }
michael@0 667 delete keywords;
michael@0 668 }
michael@0 669 }
michael@0 670
michael@0 671 if (U_FAILURE(status)) {
michael@0 672 return;
michael@0 673 }
michael@0 674
michael@0 675 if (setupForPluralPattern) {
michael@0 676 if (fPluralAffixesForCurrency) {
michael@0 677 deleteHashForAffix(fPluralAffixesForCurrency);
michael@0 678 }
michael@0 679 fPluralAffixesForCurrency = initHashForAffix(status);
michael@0 680 if (U_SUCCESS(status)) {
michael@0 681 const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules();
michael@0 682 StringEnumeration* keywords = pluralRules->getKeywords(status);
michael@0 683 if (U_SUCCESS(status)) {
michael@0 684 const UnicodeString* pluralCount;
michael@0 685 while ((pluralCount = keywords->snext(status)) != NULL) {
michael@0 686 if ( U_SUCCESS(status) ) {
michael@0 687 UnicodeString ptn;
michael@0 688 fCurrencyPluralInfo->getCurrencyPluralPattern(*pluralCount, ptn);
michael@0 689 applyPatternInternally(*pluralCount, ptn, false, parseErr, status);
michael@0 690 AffixesForCurrency* affix = new AffixesForCurrency(
michael@0 691 fNegativePrefix, fNegativeSuffix, fPositivePrefix, fPositiveSuffix);
michael@0 692 fPluralAffixesForCurrency->put(*pluralCount, affix, status);
michael@0 693 }
michael@0 694 }
michael@0 695 }
michael@0 696 delete keywords;
michael@0 697 }
michael@0 698 }
michael@0 699 }
michael@0 700
michael@0 701
michael@0 702 //------------------------------------------------------------------------------
michael@0 703
michael@0 704 DecimalFormat::~DecimalFormat()
michael@0 705 {
michael@0 706 delete fPosPrefixPattern;
michael@0 707 delete fPosSuffixPattern;
michael@0 708 delete fNegPrefixPattern;
michael@0 709 delete fNegSuffixPattern;
michael@0 710 delete fCurrencyChoice;
michael@0 711 delete fMultiplier;
michael@0 712 delete fSymbols;
michael@0 713 delete fRoundingIncrement;
michael@0 714 deleteHashForAffixPattern();
michael@0 715 deleteHashForAffix(fAffixesForCurrency);
michael@0 716 deleteHashForAffix(fPluralAffixesForCurrency);
michael@0 717 delete fCurrencyPluralInfo;
michael@0 718 }
michael@0 719
michael@0 720 //------------------------------------------------------------------------------
michael@0 721 // copy constructor
michael@0 722
michael@0 723 DecimalFormat::DecimalFormat(const DecimalFormat &source) :
michael@0 724 NumberFormat(source) {
michael@0 725 init();
michael@0 726 *this = source;
michael@0 727 }
michael@0 728
michael@0 729 //------------------------------------------------------------------------------
michael@0 730 // assignment operator
michael@0 731
michael@0 732 template <class T>
michael@0 733 static void _copy_ptr(T** pdest, const T* source) {
michael@0 734 if (source == NULL) {
michael@0 735 delete *pdest;
michael@0 736 *pdest = NULL;
michael@0 737 } else if (*pdest == NULL) {
michael@0 738 *pdest = new T(*source);
michael@0 739 } else {
michael@0 740 **pdest = *source;
michael@0 741 }
michael@0 742 }
michael@0 743
michael@0 744 template <class T>
michael@0 745 static void _clone_ptr(T** pdest, const T* source) {
michael@0 746 delete *pdest;
michael@0 747 if (source == NULL) {
michael@0 748 *pdest = NULL;
michael@0 749 } else {
michael@0 750 *pdest = static_cast<T*>(source->clone());
michael@0 751 }
michael@0 752 }
michael@0 753
michael@0 754 DecimalFormat&
michael@0 755 DecimalFormat::operator=(const DecimalFormat& rhs)
michael@0 756 {
michael@0 757 if(this != &rhs) {
michael@0 758 UErrorCode status = U_ZERO_ERROR;
michael@0 759 NumberFormat::operator=(rhs);
michael@0 760 fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
michael@0 761 fPositivePrefix = rhs.fPositivePrefix;
michael@0 762 fPositiveSuffix = rhs.fPositiveSuffix;
michael@0 763 fNegativePrefix = rhs.fNegativePrefix;
michael@0 764 fNegativeSuffix = rhs.fNegativeSuffix;
michael@0 765 _copy_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern);
michael@0 766 _copy_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern);
michael@0 767 _copy_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern);
michael@0 768 _copy_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern);
michael@0 769 _clone_ptr(&fCurrencyChoice, rhs.fCurrencyChoice);
michael@0 770 setRoundingIncrement(rhs.getRoundingIncrement());
michael@0 771 fRoundingMode = rhs.fRoundingMode;
michael@0 772 setMultiplier(rhs.getMultiplier());
michael@0 773 fGroupingSize = rhs.fGroupingSize;
michael@0 774 fGroupingSize2 = rhs.fGroupingSize2;
michael@0 775 fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown;
michael@0 776 _copy_ptr(&fSymbols, rhs.fSymbols);
michael@0 777 fUseExponentialNotation = rhs.fUseExponentialNotation;
michael@0 778 fExponentSignAlwaysShown = rhs.fExponentSignAlwaysShown;
michael@0 779 fBoolFlags = rhs.fBoolFlags;
michael@0 780 /*Bertrand A. D. Update 98.03.17*/
michael@0 781 fCurrencySignCount = rhs.fCurrencySignCount;
michael@0 782 /*end of Update*/
michael@0 783 fMinExponentDigits = rhs.fMinExponentDigits;
michael@0 784
michael@0 785 /* sfb 990629 */
michael@0 786 fFormatWidth = rhs.fFormatWidth;
michael@0 787 fPad = rhs.fPad;
michael@0 788 fPadPosition = rhs.fPadPosition;
michael@0 789 /* end sfb */
michael@0 790 fMinSignificantDigits = rhs.fMinSignificantDigits;
michael@0 791 fMaxSignificantDigits = rhs.fMaxSignificantDigits;
michael@0 792 fUseSignificantDigits = rhs.fUseSignificantDigits;
michael@0 793 fFormatPattern = rhs.fFormatPattern;
michael@0 794 fStyle = rhs.fStyle;
michael@0 795 fCurrencySignCount = rhs.fCurrencySignCount;
michael@0 796 _clone_ptr(&fCurrencyPluralInfo, rhs.fCurrencyPluralInfo);
michael@0 797 deleteHashForAffixPattern();
michael@0 798 if (rhs.fAffixPatternsForCurrency) {
michael@0 799 UErrorCode status = U_ZERO_ERROR;
michael@0 800 fAffixPatternsForCurrency = initHashForAffixPattern(status);
michael@0 801 copyHashForAffixPattern(rhs.fAffixPatternsForCurrency,
michael@0 802 fAffixPatternsForCurrency, status);
michael@0 803 }
michael@0 804 deleteHashForAffix(fAffixesForCurrency);
michael@0 805 if (rhs.fAffixesForCurrency) {
michael@0 806 UErrorCode status = U_ZERO_ERROR;
michael@0 807 fAffixesForCurrency = initHashForAffixPattern(status);
michael@0 808 copyHashForAffix(rhs.fAffixesForCurrency, fAffixesForCurrency, status);
michael@0 809 }
michael@0 810 deleteHashForAffix(fPluralAffixesForCurrency);
michael@0 811 if (rhs.fPluralAffixesForCurrency) {
michael@0 812 UErrorCode status = U_ZERO_ERROR;
michael@0 813 fPluralAffixesForCurrency = initHashForAffixPattern(status);
michael@0 814 copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCurrency, status);
michael@0 815 }
michael@0 816 }
michael@0 817 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 818 handleChanged();
michael@0 819 #endif
michael@0 820 return *this;
michael@0 821 }
michael@0 822
michael@0 823 //------------------------------------------------------------------------------
michael@0 824
michael@0 825 UBool
michael@0 826 DecimalFormat::operator==(const Format& that) const
michael@0 827 {
michael@0 828 if (this == &that)
michael@0 829 return TRUE;
michael@0 830
michael@0 831 // NumberFormat::operator== guarantees this cast is safe
michael@0 832 const DecimalFormat* other = (DecimalFormat*)&that;
michael@0 833
michael@0 834 #ifdef FMT_DEBUG
michael@0 835 // This code makes it easy to determine why two format objects that should
michael@0 836 // be equal aren't.
michael@0 837 UBool first = TRUE;
michael@0 838 if (!NumberFormat::operator==(that)) {
michael@0 839 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 840 debug("NumberFormat::!=");
michael@0 841 } else {
michael@0 842 if (!((fPosPrefixPattern == other->fPosPrefixPattern && // both null
michael@0 843 fPositivePrefix == other->fPositivePrefix)
michael@0 844 || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
michael@0 845 *fPosPrefixPattern == *other->fPosPrefixPattern))) {
michael@0 846 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 847 debug("Pos Prefix !=");
michael@0 848 }
michael@0 849 if (!((fPosSuffixPattern == other->fPosSuffixPattern && // both null
michael@0 850 fPositiveSuffix == other->fPositiveSuffix)
michael@0 851 || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
michael@0 852 *fPosSuffixPattern == *other->fPosSuffixPattern))) {
michael@0 853 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 854 debug("Pos Suffix !=");
michael@0 855 }
michael@0 856 if (!((fNegPrefixPattern == other->fNegPrefixPattern && // both null
michael@0 857 fNegativePrefix == other->fNegativePrefix)
michael@0 858 || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
michael@0 859 *fNegPrefixPattern == *other->fNegPrefixPattern))) {
michael@0 860 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 861 debug("Neg Prefix ");
michael@0 862 if (fNegPrefixPattern == NULL) {
michael@0 863 debug("NULL(");
michael@0 864 debugout(fNegativePrefix);
michael@0 865 debug(")");
michael@0 866 } else {
michael@0 867 debugout(*fNegPrefixPattern);
michael@0 868 }
michael@0 869 debug(" != ");
michael@0 870 if (other->fNegPrefixPattern == NULL) {
michael@0 871 debug("NULL(");
michael@0 872 debugout(other->fNegativePrefix);
michael@0 873 debug(")");
michael@0 874 } else {
michael@0 875 debugout(*other->fNegPrefixPattern);
michael@0 876 }
michael@0 877 }
michael@0 878 if (!((fNegSuffixPattern == other->fNegSuffixPattern && // both null
michael@0 879 fNegativeSuffix == other->fNegativeSuffix)
michael@0 880 || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
michael@0 881 *fNegSuffixPattern == *other->fNegSuffixPattern))) {
michael@0 882 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 883 debug("Neg Suffix ");
michael@0 884 if (fNegSuffixPattern == NULL) {
michael@0 885 debug("NULL(");
michael@0 886 debugout(fNegativeSuffix);
michael@0 887 debug(")");
michael@0 888 } else {
michael@0 889 debugout(*fNegSuffixPattern);
michael@0 890 }
michael@0 891 debug(" != ");
michael@0 892 if (other->fNegSuffixPattern == NULL) {
michael@0 893 debug("NULL(");
michael@0 894 debugout(other->fNegativeSuffix);
michael@0 895 debug(")");
michael@0 896 } else {
michael@0 897 debugout(*other->fNegSuffixPattern);
michael@0 898 }
michael@0 899 }
michael@0 900 if (!((fRoundingIncrement == other->fRoundingIncrement) // both null
michael@0 901 || (fRoundingIncrement != NULL &&
michael@0 902 other->fRoundingIncrement != NULL &&
michael@0 903 *fRoundingIncrement == *other->fRoundingIncrement))) {
michael@0 904 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 905 debug("Rounding Increment !=");
michael@0 906 }
michael@0 907 if (getMultiplier() != other->getMultiplier()) {
michael@0 908 if (first) { printf("[ "); first = FALSE; }
michael@0 909 printf("Multiplier %ld != %ld", getMultiplier(), other->getMultiplier());
michael@0 910 }
michael@0 911 if (fGroupingSize != other->fGroupingSize) {
michael@0 912 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 913 printf("Grouping Size %ld != %ld", fGroupingSize, other->fGroupingSize);
michael@0 914 }
michael@0 915 if (fGroupingSize2 != other->fGroupingSize2) {
michael@0 916 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 917 printf("Secondary Grouping Size %ld != %ld", fGroupingSize2, other->fGroupingSize2);
michael@0 918 }
michael@0 919 if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) {
michael@0 920 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 921 printf("Dec Sep Always %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown);
michael@0 922 }
michael@0 923 if (fUseExponentialNotation != other->fUseExponentialNotation) {
michael@0 924 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 925 debug("Use Exp !=");
michael@0 926 }
michael@0 927 if (!(!fUseExponentialNotation ||
michael@0 928 fMinExponentDigits != other->fMinExponentDigits)) {
michael@0 929 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 930 debug("Exp Digits !=");
michael@0 931 }
michael@0 932 if (*fSymbols != *(other->fSymbols)) {
michael@0 933 if (first) { printf("[ "); first = FALSE; } else { printf(", "); }
michael@0 934 debug("Symbols !=");
michael@0 935 }
michael@0 936 // TODO Add debug stuff for significant digits here
michael@0 937 if (fUseSignificantDigits != other->fUseSignificantDigits) {
michael@0 938 debug("fUseSignificantDigits !=");
michael@0 939 }
michael@0 940 if (fUseSignificantDigits &&
michael@0 941 fMinSignificantDigits != other->fMinSignificantDigits) {
michael@0 942 debug("fMinSignificantDigits !=");
michael@0 943 }
michael@0 944 if (fUseSignificantDigits &&
michael@0 945 fMaxSignificantDigits != other->fMaxSignificantDigits) {
michael@0 946 debug("fMaxSignificantDigits !=");
michael@0 947 }
michael@0 948
michael@0 949 if (!first) { printf(" ]"); }
michael@0 950 if (fCurrencySignCount != other->fCurrencySignCount) {
michael@0 951 debug("fCurrencySignCount !=");
michael@0 952 }
michael@0 953 if (fCurrencyPluralInfo == other->fCurrencyPluralInfo) {
michael@0 954 debug("fCurrencyPluralInfo == ");
michael@0 955 if (fCurrencyPluralInfo == NULL) {
michael@0 956 debug("fCurrencyPluralInfo == NULL");
michael@0 957 }
michael@0 958 }
michael@0 959 if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
michael@0 960 *fCurrencyPluralInfo != *(other->fCurrencyPluralInfo)) {
michael@0 961 debug("fCurrencyPluralInfo !=");
michael@0 962 }
michael@0 963 if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo == NULL ||
michael@0 964 fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo != NULL) {
michael@0 965 debug("fCurrencyPluralInfo one NULL, the other not");
michael@0 966 }
michael@0 967 if (fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo == NULL) {
michael@0 968 debug("fCurrencyPluralInfo == ");
michael@0 969 }
michael@0 970 }
michael@0 971 #endif
michael@0 972
michael@0 973 return (NumberFormat::operator==(that) &&
michael@0 974 ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ?
michael@0 975 (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency)) :
michael@0 976 (((fPosPrefixPattern == other->fPosPrefixPattern && // both null
michael@0 977 fPositivePrefix == other->fPositivePrefix)
michael@0 978 || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 &&
michael@0 979 *fPosPrefixPattern == *other->fPosPrefixPattern)) &&
michael@0 980 ((fPosSuffixPattern == other->fPosSuffixPattern && // both null
michael@0 981 fPositiveSuffix == other->fPositiveSuffix)
michael@0 982 || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 &&
michael@0 983 *fPosSuffixPattern == *other->fPosSuffixPattern)) &&
michael@0 984 ((fNegPrefixPattern == other->fNegPrefixPattern && // both null
michael@0 985 fNegativePrefix == other->fNegativePrefix)
michael@0 986 || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 &&
michael@0 987 *fNegPrefixPattern == *other->fNegPrefixPattern)) &&
michael@0 988 ((fNegSuffixPattern == other->fNegSuffixPattern && // both null
michael@0 989 fNegativeSuffix == other->fNegativeSuffix)
michael@0 990 || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 &&
michael@0 991 *fNegSuffixPattern == *other->fNegSuffixPattern)))) &&
michael@0 992 ((fRoundingIncrement == other->fRoundingIncrement) // both null
michael@0 993 || (fRoundingIncrement != NULL &&
michael@0 994 other->fRoundingIncrement != NULL &&
michael@0 995 *fRoundingIncrement == *other->fRoundingIncrement)) &&
michael@0 996 getMultiplier() == other->getMultiplier() &&
michael@0 997 fGroupingSize == other->fGroupingSize &&
michael@0 998 fGroupingSize2 == other->fGroupingSize2 &&
michael@0 999 fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown &&
michael@0 1000 fUseExponentialNotation == other->fUseExponentialNotation &&
michael@0 1001 (!fUseExponentialNotation ||
michael@0 1002 fMinExponentDigits == other->fMinExponentDigits) &&
michael@0 1003 *fSymbols == *(other->fSymbols) &&
michael@0 1004 fUseSignificantDigits == other->fUseSignificantDigits &&
michael@0 1005 (!fUseSignificantDigits ||
michael@0 1006 (fMinSignificantDigits == other->fMinSignificantDigits &&
michael@0 1007 fMaxSignificantDigits == other->fMaxSignificantDigits)) &&
michael@0 1008 fCurrencySignCount == other->fCurrencySignCount &&
michael@0 1009 ((fCurrencyPluralInfo == other->fCurrencyPluralInfo &&
michael@0 1010 fCurrencyPluralInfo == NULL) ||
michael@0 1011 (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL &&
michael@0 1012 *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo))));
michael@0 1013 }
michael@0 1014
michael@0 1015 //------------------------------------------------------------------------------
michael@0 1016
michael@0 1017 Format*
michael@0 1018 DecimalFormat::clone() const
michael@0 1019 {
michael@0 1020 return new DecimalFormat(*this);
michael@0 1021 }
michael@0 1022
michael@0 1023
michael@0 1024 FixedDecimal
michael@0 1025 DecimalFormat::getFixedDecimal(double number, UErrorCode &status) const {
michael@0 1026 FixedDecimal result;
michael@0 1027
michael@0 1028 if (U_FAILURE(status)) {
michael@0 1029 return result;
michael@0 1030 }
michael@0 1031
michael@0 1032 if (uprv_isNaN(number) || uprv_isPositiveInfinity(fabs(number))) {
michael@0 1033 // For NaN and Infinity the state of the formatter is ignored.
michael@0 1034 result.init(number);
michael@0 1035 return result;
michael@0 1036 }
michael@0 1037
michael@0 1038 if (fMultiplier == NULL && fScale == 0 && fRoundingIncrement == 0 && areSignificantDigitsUsed() == FALSE &&
michael@0 1039 result.quickInit(number) && result.visibleDecimalDigitCount <= getMaximumFractionDigits()) {
michael@0 1040 // Fast Path. Construction of an exact FixedDecimal directly from the double, without passing
michael@0 1041 // through a DigitList, was successful, and the formatter is doing nothing tricky with rounding.
michael@0 1042 // printf("getFixedDecimal(%g): taking fast path.\n", number);
michael@0 1043 result.adjustForMinFractionDigits(getMinimumFractionDigits());
michael@0 1044 } else {
michael@0 1045 // Slow path. Create a DigitList, and have this formatter round it according to the
michael@0 1046 // requirements of the format, and fill the fixedDecimal from that.
michael@0 1047 DigitList digits;
michael@0 1048 digits.set(number);
michael@0 1049 result = getFixedDecimal(digits, status);
michael@0 1050 }
michael@0 1051 return result;
michael@0 1052 }
michael@0 1053
michael@0 1054 // MSVC optimizer bug?
michael@0 1055 // turn off optimization as it causes different behavior in the int64->double->int64 conversion
michael@0 1056 #if defined (_MSC_VER)
michael@0 1057 #pragma optimize ( "", off )
michael@0 1058 #endif
michael@0 1059 FixedDecimal
michael@0 1060 DecimalFormat::getFixedDecimal(const Formattable &number, UErrorCode &status) const {
michael@0 1061 if (U_FAILURE(status)) {
michael@0 1062 return FixedDecimal();
michael@0 1063 }
michael@0 1064 if (!number.isNumeric()) {
michael@0 1065 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 1066 return FixedDecimal();
michael@0 1067 }
michael@0 1068
michael@0 1069 DigitList *dl = number.getDigitList();
michael@0 1070 if (dl != NULL) {
michael@0 1071 DigitList clonedDL(*dl);
michael@0 1072 return getFixedDecimal(clonedDL, status);
michael@0 1073 }
michael@0 1074
michael@0 1075 Formattable::Type type = number.getType();
michael@0 1076 if (type == Formattable::kDouble || type == Formattable::kLong) {
michael@0 1077 return getFixedDecimal(number.getDouble(status), status);
michael@0 1078 }
michael@0 1079
michael@0 1080 if (type == Formattable::kInt64) {
michael@0 1081 // "volatile" here is a workaround to avoid optimization issues.
michael@0 1082 volatile double fdv = number.getDouble(status);
michael@0 1083 // Note: conversion of int64_t -> double rounds with some compilers to
michael@0 1084 // values beyond what can be represented as a 64 bit int. Subsequent
michael@0 1085 // testing or conversion with int64_t produces bad results.
michael@0 1086 // So filter the problematic values, route them to DigitList.
michael@0 1087 if (fdv != (double)U_INT64_MAX && fdv != (double)U_INT64_MIN &&
michael@0 1088 number.getInt64() == (int64_t)fdv) {
michael@0 1089 return getFixedDecimal(number.getDouble(status), status);
michael@0 1090 }
michael@0 1091 }
michael@0 1092
michael@0 1093 // The only case left is type==int64_t, with a value with more digits than a double can represent.
michael@0 1094 // Any formattable originating as a big decimal will have had a pre-existing digit list.
michael@0 1095 // Any originating as a double or int32 will have been handled as a double.
michael@0 1096
michael@0 1097 U_ASSERT(type == Formattable::kInt64);
michael@0 1098 DigitList digits;
michael@0 1099 digits.set(number.getInt64());
michael@0 1100 return getFixedDecimal(digits, status);
michael@0 1101 }
michael@0 1102 // end workaround MSVC optimizer bug
michael@0 1103 #if defined (_MSC_VER)
michael@0 1104 #pragma optimize ( "", on )
michael@0 1105 #endif
michael@0 1106
michael@0 1107
michael@0 1108 // Create a fixed decimal from a DigitList.
michael@0 1109 // The digit list may be modified.
michael@0 1110 // Internal function only.
michael@0 1111 FixedDecimal
michael@0 1112 DecimalFormat::getFixedDecimal(DigitList &number, UErrorCode &status) const {
michael@0 1113 // Round the number according to the requirements of this Format.
michael@0 1114 FixedDecimal result;
michael@0 1115 _round(number, number, result.isNegative, status);
michael@0 1116
michael@0 1117 // The int64_t fields in FixedDecimal can easily overflow.
michael@0 1118 // In deciding what to discard in this event, consider that fixedDecimal
michael@0 1119 // is being used only with PluralRules, and those rules mostly look at least significant
michael@0 1120 // few digits of the integer part, and whether the fraction part is zero or not.
michael@0 1121 //
michael@0 1122 // So, in case of overflow when filling in the fields of the FixedDecimal object,
michael@0 1123 // for the integer part, discard the most significant digits.
michael@0 1124 // for the fraction part, discard the least significant digits,
michael@0 1125 // don't truncate the fraction value to zero.
michael@0 1126 // For simplicity, the int64_t fields are limited to 18 decimal digits, even
michael@0 1127 // though they could hold most (but not all) 19 digit values.
michael@0 1128
michael@0 1129 // Integer Digits.
michael@0 1130 int32_t di = number.getDecimalAt()-18; // Take at most 18 digits.
michael@0 1131 if (di < 0) {
michael@0 1132 di = 0;
michael@0 1133 }
michael@0 1134 result.intValue = 0;
michael@0 1135 for (; di<number.getDecimalAt(); di++) {
michael@0 1136 result.intValue = result.intValue * 10 + (number.getDigit(di) & 0x0f);
michael@0 1137 }
michael@0 1138 if (result.intValue == 0 && number.getDecimalAt()-18 > 0) {
michael@0 1139 // The number is something like 100000000000000000000000.
michael@0 1140 // More than 18 digits integer digits, but the least significant 18 are all zero.
michael@0 1141 // We don't want to return zero as the int part, but want to keep zeros
michael@0 1142 // for several of the least significant digits.
michael@0 1143 result.intValue = 100000000000000000LL;
michael@0 1144 }
michael@0 1145
michael@0 1146 // Fraction digits.
michael@0 1147 result.decimalDigits = result.decimalDigitsWithoutTrailingZeros = result.visibleDecimalDigitCount = 0;
michael@0 1148 for (di = number.getDecimalAt(); di < number.getCount(); di++) {
michael@0 1149 result.visibleDecimalDigitCount++;
michael@0 1150 if (result.decimalDigits < 100000000000000000LL) {
michael@0 1151 // 9223372036854775807 Largest 64 bit signed integer
michael@0 1152 int32_t digitVal = number.getDigit(di) & 0x0f; // getDigit() returns a char, '0'-'9'.
michael@0 1153 result.decimalDigits = result.decimalDigits * 10 + digitVal;
michael@0 1154 if (digitVal > 0) {
michael@0 1155 result.decimalDigitsWithoutTrailingZeros = result.decimalDigits;
michael@0 1156 }
michael@0 1157 }
michael@0 1158 }
michael@0 1159
michael@0 1160 result.hasIntegerValue = (result.decimalDigits == 0);
michael@0 1161
michael@0 1162 // Trailing fraction zeros. The format specification may require more trailing
michael@0 1163 // zeros than the numeric value. Add any such on now.
michael@0 1164
michael@0 1165 int32_t minFractionDigits;
michael@0 1166 if (areSignificantDigitsUsed()) {
michael@0 1167 minFractionDigits = getMinimumSignificantDigits() - number.getDecimalAt();
michael@0 1168 if (minFractionDigits < 0) {
michael@0 1169 minFractionDigits = 0;
michael@0 1170 }
michael@0 1171 } else {
michael@0 1172 minFractionDigits = getMinimumFractionDigits();
michael@0 1173 }
michael@0 1174 result.adjustForMinFractionDigits(minFractionDigits);
michael@0 1175
michael@0 1176 return result;
michael@0 1177 }
michael@0 1178
michael@0 1179
michael@0 1180 //------------------------------------------------------------------------------
michael@0 1181
michael@0 1182 UnicodeString&
michael@0 1183 DecimalFormat::format(int32_t number,
michael@0 1184 UnicodeString& appendTo,
michael@0 1185 FieldPosition& fieldPosition) const
michael@0 1186 {
michael@0 1187 return format((int64_t)number, appendTo, fieldPosition);
michael@0 1188 }
michael@0 1189
michael@0 1190 UnicodeString&
michael@0 1191 DecimalFormat::format(int32_t number,
michael@0 1192 UnicodeString& appendTo,
michael@0 1193 FieldPosition& fieldPosition,
michael@0 1194 UErrorCode& status) const
michael@0 1195 {
michael@0 1196 return format((int64_t)number, appendTo, fieldPosition, status);
michael@0 1197 }
michael@0 1198
michael@0 1199 UnicodeString&
michael@0 1200 DecimalFormat::format(int32_t number,
michael@0 1201 UnicodeString& appendTo,
michael@0 1202 FieldPositionIterator* posIter,
michael@0 1203 UErrorCode& status) const
michael@0 1204 {
michael@0 1205 return format((int64_t)number, appendTo, posIter, status);
michael@0 1206 }
michael@0 1207
michael@0 1208
michael@0 1209 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 1210 void DecimalFormat::handleChanged() {
michael@0 1211 DecimalFormatInternal &data = internalData(fReserved);
michael@0 1212
michael@0 1213 if(data.fFastFormatStatus == kFastpathUNKNOWN || data.fFastParseStatus == kFastpathUNKNOWN) {
michael@0 1214 return; // still constructing. Wait.
michael@0 1215 }
michael@0 1216
michael@0 1217 data.fFastParseStatus = data.fFastFormatStatus = kFastpathNO;
michael@0 1218
michael@0 1219 #if UCONFIG_HAVE_PARSEALLINPUT
michael@0 1220 if(fParseAllInput == UNUM_NO) {
michael@0 1221 debug("No Parse fastpath: fParseAllInput==UNUM_NO");
michael@0 1222 } else
michael@0 1223 #endif
michael@0 1224 if (fFormatWidth!=0) {
michael@0 1225 debug("No Parse fastpath: fFormatWidth");
michael@0 1226 } else if(fPositivePrefix.length()>0) {
michael@0 1227 debug("No Parse fastpath: positive prefix");
michael@0 1228 } else if(fPositiveSuffix.length()>0) {
michael@0 1229 debug("No Parse fastpath: positive suffix");
michael@0 1230 } else if(fNegativePrefix.length()>1
michael@0 1231 || ((fNegativePrefix.length()==1) && (fNegativePrefix.charAt(0)!=0x002D))) {
michael@0 1232 debug("No Parse fastpath: negative prefix that isn't '-'");
michael@0 1233 } else if(fNegativeSuffix.length()>0) {
michael@0 1234 debug("No Parse fastpath: negative suffix");
michael@0 1235 } else {
michael@0 1236 data.fFastParseStatus = kFastpathYES;
michael@0 1237 debug("parse fastpath: YES");
michael@0 1238 }
michael@0 1239
michael@0 1240 if (fGroupingSize!=0 && isGroupingUsed()) {
michael@0 1241 debug("No format fastpath: fGroupingSize!=0 and grouping is used");
michael@0 1242 #ifdef FMT_DEBUG
michael@0 1243 printf("groupingsize=%d\n", fGroupingSize);
michael@0 1244 #endif
michael@0 1245 } else if(fGroupingSize2!=0 && isGroupingUsed()) {
michael@0 1246 debug("No format fastpath: fGroupingSize2!=0");
michael@0 1247 } else if(fUseExponentialNotation) {
michael@0 1248 debug("No format fastpath: fUseExponentialNotation");
michael@0 1249 } else if(fFormatWidth!=0) {
michael@0 1250 debug("No format fastpath: fFormatWidth!=0");
michael@0 1251 } else if(fMinSignificantDigits!=1) {
michael@0 1252 debug("No format fastpath: fMinSignificantDigits!=1");
michael@0 1253 } else if(fMultiplier!=NULL) {
michael@0 1254 debug("No format fastpath: fMultiplier!=NULL");
michael@0 1255 } else if(fScale!=0) {
michael@0 1256 debug("No format fastpath: fScale!=0");
michael@0 1257 } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
michael@0 1258 debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
michael@0 1259 } else if(fDecimalSeparatorAlwaysShown) {
michael@0 1260 debug("No format fastpath: fDecimalSeparatorAlwaysShown");
michael@0 1261 } else if(getMinimumFractionDigits()>0) {
michael@0 1262 debug("No format fastpath: fMinFractionDigits>0");
michael@0 1263 } else if(fCurrencySignCount != fgCurrencySignCountZero) {
michael@0 1264 debug("No format fastpath: fCurrencySignCount != fgCurrencySignCountZero");
michael@0 1265 } else if(fRoundingIncrement!=0) {
michael@0 1266 debug("No format fastpath: fRoundingIncrement!=0");
michael@0 1267 } else {
michael@0 1268 data.fFastFormatStatus = kFastpathYES;
michael@0 1269 debug("format:kFastpathYES!");
michael@0 1270 }
michael@0 1271
michael@0 1272
michael@0 1273 }
michael@0 1274 #endif
michael@0 1275 //------------------------------------------------------------------------------
michael@0 1276
michael@0 1277 UnicodeString&
michael@0 1278 DecimalFormat::format(int64_t number,
michael@0 1279 UnicodeString& appendTo,
michael@0 1280 FieldPosition& fieldPosition) const
michael@0 1281 {
michael@0 1282 UErrorCode status = U_ZERO_ERROR; /* ignored */
michael@0 1283 FieldPositionOnlyHandler handler(fieldPosition);
michael@0 1284 return _format(number, appendTo, handler, status);
michael@0 1285 }
michael@0 1286
michael@0 1287 UnicodeString&
michael@0 1288 DecimalFormat::format(int64_t number,
michael@0 1289 UnicodeString& appendTo,
michael@0 1290 FieldPosition& fieldPosition,
michael@0 1291 UErrorCode& status) const
michael@0 1292 {
michael@0 1293 FieldPositionOnlyHandler handler(fieldPosition);
michael@0 1294 return _format(number, appendTo, handler, status);
michael@0 1295 }
michael@0 1296
michael@0 1297 UnicodeString&
michael@0 1298 DecimalFormat::format(int64_t number,
michael@0 1299 UnicodeString& appendTo,
michael@0 1300 FieldPositionIterator* posIter,
michael@0 1301 UErrorCode& status) const
michael@0 1302 {
michael@0 1303 FieldPositionIteratorHandler handler(posIter, status);
michael@0 1304 return _format(number, appendTo, handler, status);
michael@0 1305 }
michael@0 1306
michael@0 1307 UnicodeString&
michael@0 1308 DecimalFormat::_format(int64_t number,
michael@0 1309 UnicodeString& appendTo,
michael@0 1310 FieldPositionHandler& handler,
michael@0 1311 UErrorCode &status) const
michael@0 1312 {
michael@0 1313 // Bottleneck function for formatting int64_t
michael@0 1314 if (U_FAILURE(status)) {
michael@0 1315 return appendTo;
michael@0 1316 }
michael@0 1317
michael@0 1318 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 1319 // const UnicodeString *posPrefix = fPosPrefixPattern;
michael@0 1320 // const UnicodeString *posSuffix = fPosSuffixPattern;
michael@0 1321 // const UnicodeString *negSuffix = fNegSuffixPattern;
michael@0 1322
michael@0 1323 const DecimalFormatInternal &data = internalData(fReserved);
michael@0 1324
michael@0 1325 #ifdef FMT_DEBUG
michael@0 1326 data.dump();
michael@0 1327 printf("fastpath? [%d]\n", number);
michael@0 1328 #endif
michael@0 1329
michael@0 1330 if( data.fFastFormatStatus==kFastpathYES) {
michael@0 1331
michael@0 1332 #define kZero 0x0030
michael@0 1333 const int32_t MAX_IDX = MAX_DIGITS+2;
michael@0 1334 UChar outputStr[MAX_IDX];
michael@0 1335 int32_t destIdx = MAX_IDX;
michael@0 1336 outputStr[--destIdx] = 0; // term
michael@0 1337
michael@0 1338 int64_t n = number;
michael@0 1339 if (number < 1) {
michael@0 1340 // Negative numbers are slightly larger than positive
michael@0 1341 // output the first digit (or the leading zero)
michael@0 1342 outputStr[--destIdx] = (-(n % 10) + kZero);
michael@0 1343 n /= -10;
michael@0 1344 }
michael@0 1345 // get any remaining digits
michael@0 1346 while (n > 0) {
michael@0 1347 outputStr[--destIdx] = (n % 10) + kZero;
michael@0 1348 n /= 10;
michael@0 1349 }
michael@0 1350
michael@0 1351
michael@0 1352 // Slide the number to the start of the output str
michael@0 1353 U_ASSERT(destIdx >= 0);
michael@0 1354 int32_t length = MAX_IDX - destIdx -1;
michael@0 1355 /*int32_t prefixLen = */ appendAffix(appendTo, number, handler, number<0, TRUE);
michael@0 1356 int32_t maxIntDig = getMaximumIntegerDigits();
michael@0 1357 int32_t destlength = length<=maxIntDig?length:maxIntDig; // dest length pinned to max int digits
michael@0 1358
michael@0 1359 if(length>maxIntDig && fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
michael@0 1360 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 1361 }
michael@0 1362
michael@0 1363 int32_t prependZero = getMinimumIntegerDigits() - destlength;
michael@0 1364
michael@0 1365 #ifdef FMT_DEBUG
michael@0 1366 printf("prependZero=%d, length=%d, minintdig=%d maxintdig=%d destlength=%d skip=%d\n", prependZero, length, getMinimumIntegerDigits(), maxIntDig, destlength, length-destlength);
michael@0 1367 #endif
michael@0 1368 int32_t intBegin = appendTo.length();
michael@0 1369
michael@0 1370 while((prependZero--)>0) {
michael@0 1371 appendTo.append((UChar)0x0030); // '0'
michael@0 1372 }
michael@0 1373
michael@0 1374 appendTo.append(outputStr+destIdx+
michael@0 1375 (length-destlength), // skip any leading digits
michael@0 1376 destlength);
michael@0 1377 handler.addAttribute(kIntegerField, intBegin, appendTo.length());
michael@0 1378
michael@0 1379 /*int32_t suffixLen =*/ appendAffix(appendTo, number, handler, number<0, FALSE);
michael@0 1380
michael@0 1381 //outputStr[length]=0;
michael@0 1382
michael@0 1383 #ifdef FMT_DEBUG
michael@0 1384 printf("Writing [%s] length [%d] max %d for [%d]\n", outputStr+destIdx, length, MAX_IDX, number);
michael@0 1385 #endif
michael@0 1386
michael@0 1387 #undef kZero
michael@0 1388
michael@0 1389 return appendTo;
michael@0 1390 } // end fastpath
michael@0 1391 #endif
michael@0 1392
michael@0 1393 // Else the slow way - via DigitList
michael@0 1394 DigitList digits;
michael@0 1395 digits.set(number);
michael@0 1396 return _format(digits, appendTo, handler, status);
michael@0 1397 }
michael@0 1398
michael@0 1399 //------------------------------------------------------------------------------
michael@0 1400
michael@0 1401 UnicodeString&
michael@0 1402 DecimalFormat::format( double number,
michael@0 1403 UnicodeString& appendTo,
michael@0 1404 FieldPosition& fieldPosition) const
michael@0 1405 {
michael@0 1406 UErrorCode status = U_ZERO_ERROR; /* ignored */
michael@0 1407 FieldPositionOnlyHandler handler(fieldPosition);
michael@0 1408 return _format(number, appendTo, handler, status);
michael@0 1409 }
michael@0 1410
michael@0 1411 UnicodeString&
michael@0 1412 DecimalFormat::format( double number,
michael@0 1413 UnicodeString& appendTo,
michael@0 1414 FieldPosition& fieldPosition,
michael@0 1415 UErrorCode& status) const
michael@0 1416 {
michael@0 1417 FieldPositionOnlyHandler handler(fieldPosition);
michael@0 1418 return _format(number, appendTo, handler, status);
michael@0 1419 }
michael@0 1420
michael@0 1421 UnicodeString&
michael@0 1422 DecimalFormat::format( double number,
michael@0 1423 UnicodeString& appendTo,
michael@0 1424 FieldPositionIterator* posIter,
michael@0 1425 UErrorCode& status) const
michael@0 1426 {
michael@0 1427 FieldPositionIteratorHandler handler(posIter, status);
michael@0 1428 return _format(number, appendTo, handler, status);
michael@0 1429 }
michael@0 1430
michael@0 1431 UnicodeString&
michael@0 1432 DecimalFormat::_format( double number,
michael@0 1433 UnicodeString& appendTo,
michael@0 1434 FieldPositionHandler& handler,
michael@0 1435 UErrorCode &status) const
michael@0 1436 {
michael@0 1437 if (U_FAILURE(status)) {
michael@0 1438 return appendTo;
michael@0 1439 }
michael@0 1440 // Special case for NaN, sets the begin and end index to be the
michael@0 1441 // the string length of localized name of NaN.
michael@0 1442 // TODO: let NaNs go through DigitList.
michael@0 1443 if (uprv_isNaN(number))
michael@0 1444 {
michael@0 1445 int begin = appendTo.length();
michael@0 1446 appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
michael@0 1447
michael@0 1448 handler.addAttribute(kIntegerField, begin, appendTo.length());
michael@0 1449
michael@0 1450 addPadding(appendTo, handler, 0, 0);
michael@0 1451 return appendTo;
michael@0 1452 }
michael@0 1453
michael@0 1454 DigitList digits;
michael@0 1455 digits.set(number);
michael@0 1456 _format(digits, appendTo, handler, status);
michael@0 1457 // No way to return status from here.
michael@0 1458 return appendTo;
michael@0 1459 }
michael@0 1460
michael@0 1461 //------------------------------------------------------------------------------
michael@0 1462
michael@0 1463
michael@0 1464 UnicodeString&
michael@0 1465 DecimalFormat::format(const StringPiece &number,
michael@0 1466 UnicodeString &toAppendTo,
michael@0 1467 FieldPositionIterator *posIter,
michael@0 1468 UErrorCode &status) const
michael@0 1469 {
michael@0 1470 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 1471 // don't bother if the int64 path is not optimized
michael@0 1472 int32_t len = number.length();
michael@0 1473
michael@0 1474 if(len>0&&len<10) { /* 10 or more digits may not be an int64 */
michael@0 1475 const char *data = number.data();
michael@0 1476 int64_t num = 0;
michael@0 1477 UBool neg = FALSE;
michael@0 1478 UBool ok = TRUE;
michael@0 1479
michael@0 1480 int32_t start = 0;
michael@0 1481
michael@0 1482 if(data[start]=='+') {
michael@0 1483 start++;
michael@0 1484 } else if(data[start]=='-') {
michael@0 1485 neg=TRUE;
michael@0 1486 start++;
michael@0 1487 }
michael@0 1488
michael@0 1489 int32_t place = 1; /* 1, 10, ... */
michael@0 1490 for(int32_t i=len-1;i>=start;i--) {
michael@0 1491 if(data[i]>='0'&&data[i]<='9') {
michael@0 1492 num+=place*(int64_t)(data[i]-'0');
michael@0 1493 } else {
michael@0 1494 ok=FALSE;
michael@0 1495 break;
michael@0 1496 }
michael@0 1497 place *= 10;
michael@0 1498 }
michael@0 1499
michael@0 1500 if(ok) {
michael@0 1501 if(neg) {
michael@0 1502 num = -num;// add minus bit
michael@0 1503 }
michael@0 1504 // format as int64_t
michael@0 1505 return format(num, toAppendTo, posIter, status);
michael@0 1506 }
michael@0 1507 // else fall through
michael@0 1508 }
michael@0 1509 #endif
michael@0 1510
michael@0 1511 DigitList dnum;
michael@0 1512 dnum.set(number, status);
michael@0 1513 if (U_FAILURE(status)) {
michael@0 1514 return toAppendTo;
michael@0 1515 }
michael@0 1516 FieldPositionIteratorHandler handler(posIter, status);
michael@0 1517 _format(dnum, toAppendTo, handler, status);
michael@0 1518 return toAppendTo;
michael@0 1519 }
michael@0 1520
michael@0 1521
michael@0 1522 UnicodeString&
michael@0 1523 DecimalFormat::format(const DigitList &number,
michael@0 1524 UnicodeString &appendTo,
michael@0 1525 FieldPositionIterator *posIter,
michael@0 1526 UErrorCode &status) const {
michael@0 1527 FieldPositionIteratorHandler handler(posIter, status);
michael@0 1528 _format(number, appendTo, handler, status);
michael@0 1529 return appendTo;
michael@0 1530 }
michael@0 1531
michael@0 1532
michael@0 1533
michael@0 1534 UnicodeString&
michael@0 1535 DecimalFormat::format(const DigitList &number,
michael@0 1536 UnicodeString& appendTo,
michael@0 1537 FieldPosition& pos,
michael@0 1538 UErrorCode &status) const {
michael@0 1539 FieldPositionOnlyHandler handler(pos);
michael@0 1540 _format(number, appendTo, handler, status);
michael@0 1541 return appendTo;
michael@0 1542 }
michael@0 1543
michael@0 1544 DigitList&
michael@0 1545 DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& isNegative, UErrorCode &status) const {
michael@0 1546 if (U_FAILURE(status)) {
michael@0 1547 return adjustedNum;
michael@0 1548 }
michael@0 1549
michael@0 1550 // note: number and adjustedNum may refer to the same DigitList, in cases where a copy
michael@0 1551 // is not needed by the caller.
michael@0 1552
michael@0 1553 adjustedNum = number;
michael@0 1554 isNegative = false;
michael@0 1555 if (number.isNaN()) {
michael@0 1556 return adjustedNum;
michael@0 1557 }
michael@0 1558
michael@0 1559 // Do this BEFORE checking to see if value is infinite or negative! Sets the
michael@0 1560 // begin and end index to be length of the string composed of
michael@0 1561 // localized name of Infinite and the positive/negative localized
michael@0 1562 // signs.
michael@0 1563
michael@0 1564 adjustedNum.setRoundingMode(fRoundingMode);
michael@0 1565 if (fMultiplier != NULL) {
michael@0 1566 adjustedNum.mult(*fMultiplier, status);
michael@0 1567 if (U_FAILURE(status)) {
michael@0 1568 return adjustedNum;
michael@0 1569 }
michael@0 1570 }
michael@0 1571
michael@0 1572 if (fScale != 0) {
michael@0 1573 DigitList ten;
michael@0 1574 ten.set((int32_t)10);
michael@0 1575 if (fScale > 0) {
michael@0 1576 for (int32_t i = fScale ; i > 0 ; i--) {
michael@0 1577 adjustedNum.mult(ten, status);
michael@0 1578 if (U_FAILURE(status)) {
michael@0 1579 return adjustedNum;
michael@0 1580 }
michael@0 1581 }
michael@0 1582 } else {
michael@0 1583 for (int32_t i = fScale ; i < 0 ; i++) {
michael@0 1584 adjustedNum.div(ten, status);
michael@0 1585 if (U_FAILURE(status)) {
michael@0 1586 return adjustedNum;
michael@0 1587 }
michael@0 1588 }
michael@0 1589 }
michael@0 1590 }
michael@0 1591
michael@0 1592 /*
michael@0 1593 * Note: sign is important for zero as well as non-zero numbers.
michael@0 1594 * Proper detection of -0.0 is needed to deal with the
michael@0 1595 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
michael@0 1596 */
michael@0 1597 isNegative = !adjustedNum.isPositive();
michael@0 1598
michael@0 1599 // Apply rounding after multiplier
michael@0 1600
michael@0 1601 adjustedNum.fContext.status &= ~DEC_Inexact;
michael@0 1602 if (fRoundingIncrement != NULL) {
michael@0 1603 adjustedNum.div(*fRoundingIncrement, status);
michael@0 1604 adjustedNum.toIntegralValue();
michael@0 1605 adjustedNum.mult(*fRoundingIncrement, status);
michael@0 1606 adjustedNum.trim();
michael@0 1607 if (U_FAILURE(status)) {
michael@0 1608 return adjustedNum;
michael@0 1609 }
michael@0 1610 }
michael@0 1611 if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
michael@0 1612 status = U_FORMAT_INEXACT_ERROR;
michael@0 1613 return adjustedNum;
michael@0 1614 }
michael@0 1615
michael@0 1616 if (adjustedNum.isInfinite()) {
michael@0 1617 return adjustedNum;
michael@0 1618 }
michael@0 1619
michael@0 1620 if (fUseExponentialNotation || areSignificantDigitsUsed()) {
michael@0 1621 int32_t sigDigits = precision();
michael@0 1622 if (sigDigits > 0) {
michael@0 1623 adjustedNum.round(sigDigits);
michael@0 1624 }
michael@0 1625 } else {
michael@0 1626 // Fixed point format. Round to a set number of fraction digits.
michael@0 1627 int32_t numFractionDigits = precision();
michael@0 1628 adjustedNum.roundFixedPoint(numFractionDigits);
michael@0 1629 }
michael@0 1630 if (fRoundingMode == kRoundUnnecessary && (adjustedNum.fContext.status & DEC_Inexact)) {
michael@0 1631 status = U_FORMAT_INEXACT_ERROR;
michael@0 1632 return adjustedNum;
michael@0 1633 }
michael@0 1634 return adjustedNum;
michael@0 1635 }
michael@0 1636
michael@0 1637 UnicodeString&
michael@0 1638 DecimalFormat::_format(const DigitList &number,
michael@0 1639 UnicodeString& appendTo,
michael@0 1640 FieldPositionHandler& handler,
michael@0 1641 UErrorCode &status) const
michael@0 1642 {
michael@0 1643 if (U_FAILURE(status)) {
michael@0 1644 return appendTo;
michael@0 1645 }
michael@0 1646
michael@0 1647 // Special case for NaN, sets the begin and end index to be the
michael@0 1648 // the string length of localized name of NaN.
michael@0 1649 if (number.isNaN())
michael@0 1650 {
michael@0 1651 int begin = appendTo.length();
michael@0 1652 appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
michael@0 1653
michael@0 1654 handler.addAttribute(kIntegerField, begin, appendTo.length());
michael@0 1655
michael@0 1656 addPadding(appendTo, handler, 0, 0);
michael@0 1657 return appendTo;
michael@0 1658 }
michael@0 1659
michael@0 1660 DigitList adjustedNum;
michael@0 1661 UBool isNegative;
michael@0 1662 _round(number, adjustedNum, isNegative, status);
michael@0 1663 if (U_FAILURE(status)) {
michael@0 1664 return appendTo;
michael@0 1665 }
michael@0 1666
michael@0 1667 // Special case for INFINITE,
michael@0 1668 if (adjustedNum.isInfinite()) {
michael@0 1669 int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, TRUE);
michael@0 1670
michael@0 1671 int begin = appendTo.length();
michael@0 1672 appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
michael@0 1673
michael@0 1674 handler.addAttribute(kIntegerField, begin, appendTo.length());
michael@0 1675
michael@0 1676 int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handler, isNegative, FALSE);
michael@0 1677
michael@0 1678 addPadding(appendTo, handler, prefixLen, suffixLen);
michael@0 1679 return appendTo;
michael@0 1680 }
michael@0 1681 return subformat(appendTo, handler, adjustedNum, FALSE, status);
michael@0 1682 }
michael@0 1683
michael@0 1684 /**
michael@0 1685 * Return true if a grouping separator belongs at the given
michael@0 1686 * position, based on whether grouping is in use and the values of
michael@0 1687 * the primary and secondary grouping interval.
michael@0 1688 * @param pos the number of integer digits to the right of
michael@0 1689 * the current position. Zero indicates the position after the
michael@0 1690 * rightmost integer digit.
michael@0 1691 * @return true if a grouping character belongs at the current
michael@0 1692 * position.
michael@0 1693 */
michael@0 1694 UBool DecimalFormat::isGroupingPosition(int32_t pos) const {
michael@0 1695 UBool result = FALSE;
michael@0 1696 if (isGroupingUsed() && (pos > 0) && (fGroupingSize > 0)) {
michael@0 1697 if ((fGroupingSize2 > 0) && (pos > fGroupingSize)) {
michael@0 1698 result = ((pos - fGroupingSize) % fGroupingSize2) == 0;
michael@0 1699 } else {
michael@0 1700 result = pos % fGroupingSize == 0;
michael@0 1701 }
michael@0 1702 }
michael@0 1703 return result;
michael@0 1704 }
michael@0 1705
michael@0 1706 //------------------------------------------------------------------------------
michael@0 1707
michael@0 1708 /**
michael@0 1709 * Complete the formatting of a finite number. On entry, the DigitList must
michael@0 1710 * be filled in with the correct digits.
michael@0 1711 */
michael@0 1712 UnicodeString&
michael@0 1713 DecimalFormat::subformat(UnicodeString& appendTo,
michael@0 1714 FieldPositionHandler& handler,
michael@0 1715 DigitList& digits,
michael@0 1716 UBool isInteger,
michael@0 1717 UErrorCode& status) const
michael@0 1718 {
michael@0 1719 // char zero = '0';
michael@0 1720 // DigitList returns digits as '0' thru '9', so we will need to
michael@0 1721 // always need to subtract the character 0 to get the numeric value to use for indexing.
michael@0 1722
michael@0 1723 UChar32 localizedDigits[10];
michael@0 1724 localizedDigits[0] = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
michael@0 1725 localizedDigits[1] = getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
michael@0 1726 localizedDigits[2] = getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
michael@0 1727 localizedDigits[3] = getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
michael@0 1728 localizedDigits[4] = getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
michael@0 1729 localizedDigits[5] = getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
michael@0 1730 localizedDigits[6] = getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
michael@0 1731 localizedDigits[7] = getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
michael@0 1732 localizedDigits[8] = getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
michael@0 1733 localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
michael@0 1734
michael@0 1735 const UnicodeString *grouping ;
michael@0 1736 if(fCurrencySignCount == fgCurrencySignCountZero) {
michael@0 1737 grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
michael@0 1738 }else{
michael@0 1739 grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
michael@0 1740 }
michael@0 1741 const UnicodeString *decimal;
michael@0 1742 if(fCurrencySignCount == fgCurrencySignCountZero) {
michael@0 1743 decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
michael@0 1744 } else {
michael@0 1745 decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
michael@0 1746 }
michael@0 1747 UBool useSigDig = areSignificantDigitsUsed();
michael@0 1748 int32_t maxIntDig = getMaximumIntegerDigits();
michael@0 1749 int32_t minIntDig = getMinimumIntegerDigits();
michael@0 1750
michael@0 1751 // Appends the prefix.
michael@0 1752 double doubleValue = digits.getDouble();
michael@0 1753 int32_t prefixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), TRUE);
michael@0 1754
michael@0 1755 if (fUseExponentialNotation)
michael@0 1756 {
michael@0 1757 int currentLength = appendTo.length();
michael@0 1758 int intBegin = currentLength;
michael@0 1759 int intEnd = -1;
michael@0 1760 int fracBegin = -1;
michael@0 1761
michael@0 1762 int32_t minFracDig = 0;
michael@0 1763 if (useSigDig) {
michael@0 1764 maxIntDig = minIntDig = 1;
michael@0 1765 minFracDig = getMinimumSignificantDigits() - 1;
michael@0 1766 } else {
michael@0 1767 minFracDig = getMinimumFractionDigits();
michael@0 1768 if (maxIntDig > kMaxScientificIntegerDigits) {
michael@0 1769 maxIntDig = 1;
michael@0 1770 if (maxIntDig < minIntDig) {
michael@0 1771 maxIntDig = minIntDig;
michael@0 1772 }
michael@0 1773 }
michael@0 1774 if (maxIntDig > minIntDig) {
michael@0 1775 minIntDig = 1;
michael@0 1776 }
michael@0 1777 }
michael@0 1778
michael@0 1779 // Minimum integer digits are handled in exponential format by
michael@0 1780 // adjusting the exponent. For example, 0.01234 with 3 minimum
michael@0 1781 // integer digits is "123.4E-4".
michael@0 1782
michael@0 1783 // Maximum integer digits are interpreted as indicating the
michael@0 1784 // repeating range. This is useful for engineering notation, in
michael@0 1785 // which the exponent is restricted to a multiple of 3. For
michael@0 1786 // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
michael@0 1787 // If maximum integer digits are defined and are larger than
michael@0 1788 // minimum integer digits, then minimum integer digits are
michael@0 1789 // ignored.
michael@0 1790 digits.reduce(); // Removes trailing zero digits.
michael@0 1791 int32_t exponent = digits.getDecimalAt();
michael@0 1792 if (maxIntDig > 1 && maxIntDig != minIntDig) {
michael@0 1793 // A exponent increment is defined; adjust to it.
michael@0 1794 exponent = (exponent > 0) ? (exponent - 1) / maxIntDig
michael@0 1795 : (exponent / maxIntDig) - 1;
michael@0 1796 exponent *= maxIntDig;
michael@0 1797 } else {
michael@0 1798 // No exponent increment is defined; use minimum integer digits.
michael@0 1799 // If none is specified, as in "#E0", generate 1 integer digit.
michael@0 1800 exponent -= (minIntDig > 0 || minFracDig > 0)
michael@0 1801 ? minIntDig : 1;
michael@0 1802 }
michael@0 1803
michael@0 1804 // We now output a minimum number of digits, and more if there
michael@0 1805 // are more digits, up to the maximum number of digits. We
michael@0 1806 // place the decimal point after the "integer" digits, which
michael@0 1807 // are the first (decimalAt - exponent) digits.
michael@0 1808 int32_t minimumDigits = minIntDig + minFracDig;
michael@0 1809 // The number of integer digits is handled specially if the number
michael@0 1810 // is zero, since then there may be no digits.
michael@0 1811 int32_t integerDigits = digits.isZero() ? minIntDig :
michael@0 1812 digits.getDecimalAt() - exponent;
michael@0 1813 int32_t totalDigits = digits.getCount();
michael@0 1814 if (minimumDigits > totalDigits)
michael@0 1815 totalDigits = minimumDigits;
michael@0 1816 if (integerDigits > totalDigits)
michael@0 1817 totalDigits = integerDigits;
michael@0 1818
michael@0 1819 // totalDigits records total number of digits needs to be processed
michael@0 1820 int32_t i;
michael@0 1821 for (i=0; i<totalDigits; ++i)
michael@0 1822 {
michael@0 1823 if (i == integerDigits)
michael@0 1824 {
michael@0 1825 intEnd = appendTo.length();
michael@0 1826 handler.addAttribute(kIntegerField, intBegin, intEnd);
michael@0 1827
michael@0 1828 appendTo += *decimal;
michael@0 1829
michael@0 1830 fracBegin = appendTo.length();
michael@0 1831 handler.addAttribute(kDecimalSeparatorField, fracBegin - 1, fracBegin);
michael@0 1832 }
michael@0 1833 // Restores the digit character or pads the buffer with zeros.
michael@0 1834 UChar32 c = (UChar32)((i < digits.getCount()) ?
michael@0 1835 localizedDigits[digits.getDigitValue(i)] :
michael@0 1836 localizedDigits[0]);
michael@0 1837 appendTo += c;
michael@0 1838 }
michael@0 1839
michael@0 1840 currentLength = appendTo.length();
michael@0 1841
michael@0 1842 if (intEnd < 0) {
michael@0 1843 handler.addAttribute(kIntegerField, intBegin, currentLength);
michael@0 1844 }
michael@0 1845 if (fracBegin > 0) {
michael@0 1846 handler.addAttribute(kFractionField, fracBegin, currentLength);
michael@0 1847 }
michael@0 1848
michael@0 1849 // The exponent is output using the pattern-specified minimum
michael@0 1850 // exponent digits. There is no maximum limit to the exponent
michael@0 1851 // digits, since truncating the exponent would appendTo in an
michael@0 1852 // unacceptable inaccuracy.
michael@0 1853 appendTo += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
michael@0 1854
michael@0 1855 handler.addAttribute(kExponentSymbolField, currentLength, appendTo.length());
michael@0 1856 currentLength = appendTo.length();
michael@0 1857
michael@0 1858 // For zero values, we force the exponent to zero. We
michael@0 1859 // must do this here, and not earlier, because the value
michael@0 1860 // is used to determine integer digit count above.
michael@0 1861 if (digits.isZero())
michael@0 1862 exponent = 0;
michael@0 1863
michael@0 1864 if (exponent < 0) {
michael@0 1865 appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
michael@0 1866 handler.addAttribute(kExponentSignField, currentLength, appendTo.length());
michael@0 1867 } else if (fExponentSignAlwaysShown) {
michael@0 1868 appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
michael@0 1869 handler.addAttribute(kExponentSignField, currentLength, appendTo.length());
michael@0 1870 }
michael@0 1871
michael@0 1872 currentLength = appendTo.length();
michael@0 1873
michael@0 1874 DigitList expDigits;
michael@0 1875 expDigits.set(exponent);
michael@0 1876 {
michael@0 1877 int expDig = fMinExponentDigits;
michael@0 1878 if (fUseExponentialNotation && expDig < 1) {
michael@0 1879 expDig = 1;
michael@0 1880 }
michael@0 1881 for (i=expDigits.getDecimalAt(); i<expDig; ++i)
michael@0 1882 appendTo += (localizedDigits[0]);
michael@0 1883 }
michael@0 1884 for (i=0; i<expDigits.getDecimalAt(); ++i)
michael@0 1885 {
michael@0 1886 UChar32 c = (UChar32)((i < expDigits.getCount()) ?
michael@0 1887 localizedDigits[expDigits.getDigitValue(i)] :
michael@0 1888 localizedDigits[0]);
michael@0 1889 appendTo += c;
michael@0 1890 }
michael@0 1891
michael@0 1892 handler.addAttribute(kExponentField, currentLength, appendTo.length());
michael@0 1893 }
michael@0 1894 else // Not using exponential notation
michael@0 1895 {
michael@0 1896 int currentLength = appendTo.length();
michael@0 1897 int intBegin = currentLength;
michael@0 1898
michael@0 1899 int32_t sigCount = 0;
michael@0 1900 int32_t minSigDig = getMinimumSignificantDigits();
michael@0 1901 int32_t maxSigDig = getMaximumSignificantDigits();
michael@0 1902 if (!useSigDig) {
michael@0 1903 minSigDig = 0;
michael@0 1904 maxSigDig = INT32_MAX;
michael@0 1905 }
michael@0 1906
michael@0 1907 // Output the integer portion. Here 'count' is the total
michael@0 1908 // number of integer digits we will display, including both
michael@0 1909 // leading zeros required to satisfy getMinimumIntegerDigits,
michael@0 1910 // and actual digits present in the number.
michael@0 1911 int32_t count = useSigDig ?
michael@0 1912 _max(1, digits.getDecimalAt()) : minIntDig;
michael@0 1913 if (digits.getDecimalAt() > 0 && count < digits.getDecimalAt()) {
michael@0 1914 count = digits.getDecimalAt();
michael@0 1915 }
michael@0 1916
michael@0 1917 // Handle the case where getMaximumIntegerDigits() is smaller
michael@0 1918 // than the real number of integer digits. If this is so, we
michael@0 1919 // output the least significant max integer digits. For example,
michael@0 1920 // the value 1997 printed with 2 max integer digits is just "97".
michael@0 1921
michael@0 1922 int32_t digitIndex = 0; // Index into digitList.fDigits[]
michael@0 1923 if (count > maxIntDig && maxIntDig >= 0) {
michael@0 1924 count = maxIntDig;
michael@0 1925 digitIndex = digits.getDecimalAt() - count;
michael@0 1926 if(fBoolFlags.contains(UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS)) {
michael@0 1927 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 1928 }
michael@0 1929 }
michael@0 1930
michael@0 1931 int32_t sizeBeforeIntegerPart = appendTo.length();
michael@0 1932
michael@0 1933 int32_t i;
michael@0 1934 for (i=count-1; i>=0; --i)
michael@0 1935 {
michael@0 1936 if (i < digits.getDecimalAt() && digitIndex < digits.getCount() &&
michael@0 1937 sigCount < maxSigDig) {
michael@0 1938 // Output a real digit
michael@0 1939 appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)];
michael@0 1940 ++sigCount;
michael@0 1941 }
michael@0 1942 else
michael@0 1943 {
michael@0 1944 // Output a zero (leading or trailing)
michael@0 1945 appendTo += localizedDigits[0];
michael@0 1946 if (sigCount > 0) {
michael@0 1947 ++sigCount;
michael@0 1948 }
michael@0 1949 }
michael@0 1950
michael@0 1951 // Output grouping separator if necessary.
michael@0 1952 if (isGroupingPosition(i)) {
michael@0 1953 currentLength = appendTo.length();
michael@0 1954 appendTo.append(*grouping);
michael@0 1955 handler.addAttribute(kGroupingSeparatorField, currentLength, appendTo.length());
michael@0 1956 }
michael@0 1957 }
michael@0 1958
michael@0 1959 // This handles the special case of formatting 0. For zero only, we count the
michael@0 1960 // zero to the left of the decimal point as one signficant digit. Ordinarily we
michael@0 1961 // do not count any leading 0's as significant. If the number we are formatting
michael@0 1962 // is not zero, then either sigCount or digits.getCount() will be non-zero.
michael@0 1963 if (sigCount == 0 && digits.getCount() == 0) {
michael@0 1964 sigCount = 1;
michael@0 1965 }
michael@0 1966
michael@0 1967 // TODO(dlf): this looks like it was a bug, we marked the int field as ending
michael@0 1968 // before the zero was generated.
michael@0 1969 // Record field information for caller.
michael@0 1970 // if (fieldPosition.getField() == NumberFormat::kIntegerField)
michael@0 1971 // fieldPosition.setEndIndex(appendTo.length());
michael@0 1972
michael@0 1973 // Determine whether or not there are any printable fractional
michael@0 1974 // digits. If we've used up the digits we know there aren't.
michael@0 1975 UBool fractionPresent = (!isInteger && digitIndex < digits.getCount()) ||
michael@0 1976 (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() > 0));
michael@0 1977
michael@0 1978 // If there is no fraction present, and we haven't printed any
michael@0 1979 // integer digits, then print a zero. Otherwise we won't print
michael@0 1980 // _any_ digits, and we won't be able to parse this string.
michael@0 1981 if (!fractionPresent && appendTo.length() == sizeBeforeIntegerPart)
michael@0 1982 appendTo += localizedDigits[0];
michael@0 1983
michael@0 1984 currentLength = appendTo.length();
michael@0 1985 handler.addAttribute(kIntegerField, intBegin, currentLength);
michael@0 1986
michael@0 1987 // Output the decimal separator if we always do so.
michael@0 1988 if (fDecimalSeparatorAlwaysShown || fractionPresent) {
michael@0 1989 appendTo += *decimal;
michael@0 1990 handler.addAttribute(kDecimalSeparatorField, currentLength, appendTo.length());
michael@0 1991 currentLength = appendTo.length();
michael@0 1992 }
michael@0 1993
michael@0 1994 int fracBegin = currentLength;
michael@0 1995
michael@0 1996 count = useSigDig ? INT32_MAX : getMaximumFractionDigits();
michael@0 1997 if (useSigDig && (sigCount == maxSigDig ||
michael@0 1998 (sigCount >= minSigDig && digitIndex == digits.getCount()))) {
michael@0 1999 count = 0;
michael@0 2000 }
michael@0 2001
michael@0 2002 for (i=0; i < count; ++i) {
michael@0 2003 // Here is where we escape from the loop. We escape
michael@0 2004 // if we've output the maximum fraction digits
michael@0 2005 // (specified in the for expression above). We also
michael@0 2006 // stop when we've output the minimum digits and
michael@0 2007 // either: we have an integer, so there is no
michael@0 2008 // fractional stuff to display, or we're out of
michael@0 2009 // significant digits.
michael@0 2010 if (!useSigDig && i >= getMinimumFractionDigits() &&
michael@0 2011 (isInteger || digitIndex >= digits.getCount())) {
michael@0 2012 break;
michael@0 2013 }
michael@0 2014
michael@0 2015 // Output leading fractional zeros. These are zeros
michael@0 2016 // that come after the decimal but before any
michael@0 2017 // significant digits. These are only output if
michael@0 2018 // abs(number being formatted) < 1.0.
michael@0 2019 if (-1-i > (digits.getDecimalAt()-1)) {
michael@0 2020 appendTo += localizedDigits[0];
michael@0 2021 continue;
michael@0 2022 }
michael@0 2023
michael@0 2024 // Output a digit, if we have any precision left, or a
michael@0 2025 // zero if we don't. We don't want to output noise digits.
michael@0 2026 if (!isInteger && digitIndex < digits.getCount()) {
michael@0 2027 appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitIndex++)];
michael@0 2028 } else {
michael@0 2029 appendTo += localizedDigits[0];
michael@0 2030 }
michael@0 2031
michael@0 2032 // If we reach the maximum number of significant
michael@0 2033 // digits, or if we output all the real digits and
michael@0 2034 // reach the minimum, then we are done.
michael@0 2035 ++sigCount;
michael@0 2036 if (useSigDig &&
michael@0 2037 (sigCount == maxSigDig ||
michael@0 2038 (digitIndex == digits.getCount() && sigCount >= minSigDig))) {
michael@0 2039 break;
michael@0 2040 }
michael@0 2041 }
michael@0 2042
michael@0 2043 handler.addAttribute(kFractionField, fracBegin, appendTo.length());
michael@0 2044 }
michael@0 2045
michael@0 2046 int32_t suffixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPositive(), FALSE);
michael@0 2047
michael@0 2048 addPadding(appendTo, handler, prefixLen, suffixLen);
michael@0 2049 return appendTo;
michael@0 2050 }
michael@0 2051
michael@0 2052 /**
michael@0 2053 * Inserts the character fPad as needed to expand result to fFormatWidth.
michael@0 2054 * @param result the string to be padded
michael@0 2055 */
michael@0 2056 void DecimalFormat::addPadding(UnicodeString& appendTo,
michael@0 2057 FieldPositionHandler& handler,
michael@0 2058 int32_t prefixLen,
michael@0 2059 int32_t suffixLen) const
michael@0 2060 {
michael@0 2061 if (fFormatWidth > 0) {
michael@0 2062 int32_t len = fFormatWidth - appendTo.length();
michael@0 2063 if (len > 0) {
michael@0 2064 UnicodeString padding;
michael@0 2065 for (int32_t i=0; i<len; ++i) {
michael@0 2066 padding += fPad;
michael@0 2067 }
michael@0 2068 switch (fPadPosition) {
michael@0 2069 case kPadAfterPrefix:
michael@0 2070 appendTo.insert(prefixLen, padding);
michael@0 2071 break;
michael@0 2072 case kPadBeforePrefix:
michael@0 2073 appendTo.insert(0, padding);
michael@0 2074 break;
michael@0 2075 case kPadBeforeSuffix:
michael@0 2076 appendTo.insert(appendTo.length() - suffixLen, padding);
michael@0 2077 break;
michael@0 2078 case kPadAfterSuffix:
michael@0 2079 appendTo += padding;
michael@0 2080 break;
michael@0 2081 }
michael@0 2082 if (fPadPosition == kPadBeforePrefix || fPadPosition == kPadAfterPrefix) {
michael@0 2083 handler.shiftLast(len);
michael@0 2084 }
michael@0 2085 }
michael@0 2086 }
michael@0 2087 }
michael@0 2088
michael@0 2089 //------------------------------------------------------------------------------
michael@0 2090
michael@0 2091 void
michael@0 2092 DecimalFormat::parse(const UnicodeString& text,
michael@0 2093 Formattable& result,
michael@0 2094 ParsePosition& parsePosition) const {
michael@0 2095 parse(text, result, parsePosition, NULL);
michael@0 2096 }
michael@0 2097
michael@0 2098 CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text,
michael@0 2099 ParsePosition& pos) const {
michael@0 2100 Formattable parseResult;
michael@0 2101 int32_t start = pos.getIndex();
michael@0 2102 UChar curbuf[4] = {};
michael@0 2103 parse(text, parseResult, pos, curbuf);
michael@0 2104 if (pos.getIndex() != start) {
michael@0 2105 UErrorCode ec = U_ZERO_ERROR;
michael@0 2106 LocalPointer<CurrencyAmount> currAmt(new CurrencyAmount(parseResult, curbuf, ec));
michael@0 2107 if (U_FAILURE(ec)) {
michael@0 2108 pos.setIndex(start); // indicate failure
michael@0 2109 } else {
michael@0 2110 return currAmt.orphan();
michael@0 2111 }
michael@0 2112 }
michael@0 2113 return NULL;
michael@0 2114 }
michael@0 2115
michael@0 2116 /**
michael@0 2117 * Parses the given text as a number, optionally providing a currency amount.
michael@0 2118 * @param text the string to parse
michael@0 2119 * @param result output parameter for the numeric result.
michael@0 2120 * @param parsePosition input-output position; on input, the
michael@0 2121 * position within text to match; must have 0 <= pos.getIndex() <
michael@0 2122 * text.length(); on output, the position after the last matched
michael@0 2123 * character. If the parse fails, the position in unchanged upon
michael@0 2124 * output.
michael@0 2125 * @param currency if non-NULL, it should point to a 4-UChar buffer.
michael@0 2126 * In this case the text is parsed as a currency format, and the
michael@0 2127 * ISO 4217 code for the parsed currency is put into the buffer.
michael@0 2128 * Otherwise the text is parsed as a non-currency format.
michael@0 2129 */
michael@0 2130 void DecimalFormat::parse(const UnicodeString& text,
michael@0 2131 Formattable& result,
michael@0 2132 ParsePosition& parsePosition,
michael@0 2133 UChar* currency) const {
michael@0 2134 int32_t startIdx, backup;
michael@0 2135 int32_t i = startIdx = backup = parsePosition.getIndex();
michael@0 2136
michael@0 2137 // clear any old contents in the result. In particular, clears any DigitList
michael@0 2138 // that it may be holding.
michael@0 2139 result.setLong(0);
michael@0 2140 if (currency != NULL) {
michael@0 2141 for (int32_t ci=0; ci<4; ci++) {
michael@0 2142 currency[ci] = 0;
michael@0 2143 }
michael@0 2144 }
michael@0 2145
michael@0 2146 // Handle NaN as a special case:
michael@0 2147
michael@0 2148 // Skip padding characters, if around prefix
michael@0 2149 if (fFormatWidth > 0 && (fPadPosition == kPadBeforePrefix ||
michael@0 2150 fPadPosition == kPadAfterPrefix)) {
michael@0 2151 i = skipPadding(text, i);
michael@0 2152 }
michael@0 2153
michael@0 2154 if (isLenient()) {
michael@0 2155 // skip any leading whitespace
michael@0 2156 i = backup = skipUWhiteSpace(text, i);
michael@0 2157 }
michael@0 2158
michael@0 2159 // If the text is composed of the representation of NaN, returns NaN.length
michael@0 2160 const UnicodeString *nan = &getConstSymbol(DecimalFormatSymbols::kNaNSymbol);
michael@0 2161 int32_t nanLen = (text.compare(i, nan->length(), *nan)
michael@0 2162 ? 0 : nan->length());
michael@0 2163 if (nanLen) {
michael@0 2164 i += nanLen;
michael@0 2165 if (fFormatWidth > 0 && (fPadPosition == kPadBeforeSuffix ||
michael@0 2166 fPadPosition == kPadAfterSuffix)) {
michael@0 2167 i = skipPadding(text, i);
michael@0 2168 }
michael@0 2169 parsePosition.setIndex(i);
michael@0 2170 result.setDouble(uprv_getNaN());
michael@0 2171 return;
michael@0 2172 }
michael@0 2173
michael@0 2174 // NaN parse failed; start over
michael@0 2175 i = backup;
michael@0 2176 parsePosition.setIndex(i);
michael@0 2177
michael@0 2178 // status is used to record whether a number is infinite.
michael@0 2179 UBool status[fgStatusLength];
michael@0 2180
michael@0 2181 DigitList *digits = result.getInternalDigitList(); // get one from the stack buffer
michael@0 2182 if (digits == NULL) {
michael@0 2183 return; // no way to report error from here.
michael@0 2184 }
michael@0 2185
michael@0 2186 if (fCurrencySignCount != fgCurrencySignCountZero) {
michael@0 2187 if (!parseForCurrency(text, parsePosition, *digits,
michael@0 2188 status, currency)) {
michael@0 2189 return;
michael@0 2190 }
michael@0 2191 } else {
michael@0 2192 if (!subparse(text,
michael@0 2193 fNegPrefixPattern, fNegSuffixPattern,
michael@0 2194 fPosPrefixPattern, fPosSuffixPattern,
michael@0 2195 FALSE, UCURR_SYMBOL_NAME,
michael@0 2196 parsePosition, *digits, status, currency)) {
michael@0 2197 debug("!subparse(...) - rewind");
michael@0 2198 parsePosition.setIndex(startIdx);
michael@0 2199 return;
michael@0 2200 }
michael@0 2201 }
michael@0 2202
michael@0 2203 // Handle infinity
michael@0 2204 if (status[fgStatusInfinite]) {
michael@0 2205 double inf = uprv_getInfinity();
michael@0 2206 result.setDouble(digits->isPositive() ? inf : -inf);
michael@0 2207 // TODO: set the dl to infinity, and let it fall into the code below.
michael@0 2208 }
michael@0 2209
michael@0 2210 else {
michael@0 2211
michael@0 2212 if (fMultiplier != NULL) {
michael@0 2213 UErrorCode ec = U_ZERO_ERROR;
michael@0 2214 digits->div(*fMultiplier, ec);
michael@0 2215 }
michael@0 2216
michael@0 2217 if (fScale != 0) {
michael@0 2218 DigitList ten;
michael@0 2219 ten.set((int32_t)10);
michael@0 2220 if (fScale > 0) {
michael@0 2221 for (int32_t i = fScale; i > 0; i--) {
michael@0 2222 UErrorCode ec = U_ZERO_ERROR;
michael@0 2223 digits->div(ten,ec);
michael@0 2224 }
michael@0 2225 } else {
michael@0 2226 for (int32_t i = fScale; i < 0; i++) {
michael@0 2227 UErrorCode ec = U_ZERO_ERROR;
michael@0 2228 digits->mult(ten,ec);
michael@0 2229 }
michael@0 2230 }
michael@0 2231 }
michael@0 2232
michael@0 2233 // Negative zero special case:
michael@0 2234 // if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
michael@0 2235 // if not parsing integerOnly, leave as -0, which a double can represent.
michael@0 2236 if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) {
michael@0 2237 digits->setPositive(TRUE);
michael@0 2238 }
michael@0 2239 result.adoptDigitList(digits);
michael@0 2240 }
michael@0 2241 }
michael@0 2242
michael@0 2243
michael@0 2244
michael@0 2245 UBool
michael@0 2246 DecimalFormat::parseForCurrency(const UnicodeString& text,
michael@0 2247 ParsePosition& parsePosition,
michael@0 2248 DigitList& digits,
michael@0 2249 UBool* status,
michael@0 2250 UChar* currency) const {
michael@0 2251 int origPos = parsePosition.getIndex();
michael@0 2252 int maxPosIndex = origPos;
michael@0 2253 int maxErrorPos = -1;
michael@0 2254 // First, parse against current pattern.
michael@0 2255 // Since current pattern could be set by applyPattern(),
michael@0 2256 // it could be an arbitrary pattern, and it may not be the one
michael@0 2257 // defined in current locale.
michael@0 2258 UBool tmpStatus[fgStatusLength];
michael@0 2259 ParsePosition tmpPos(origPos);
michael@0 2260 DigitList tmpDigitList;
michael@0 2261 UBool found;
michael@0 2262 if (fStyle == UNUM_CURRENCY_PLURAL) {
michael@0 2263 found = subparse(text,
michael@0 2264 fNegPrefixPattern, fNegSuffixPattern,
michael@0 2265 fPosPrefixPattern, fPosSuffixPattern,
michael@0 2266 TRUE, UCURR_LONG_NAME,
michael@0 2267 tmpPos, tmpDigitList, tmpStatus, currency);
michael@0 2268 } else {
michael@0 2269 found = subparse(text,
michael@0 2270 fNegPrefixPattern, fNegSuffixPattern,
michael@0 2271 fPosPrefixPattern, fPosSuffixPattern,
michael@0 2272 TRUE, UCURR_SYMBOL_NAME,
michael@0 2273 tmpPos, tmpDigitList, tmpStatus, currency);
michael@0 2274 }
michael@0 2275 if (found) {
michael@0 2276 if (tmpPos.getIndex() > maxPosIndex) {
michael@0 2277 maxPosIndex = tmpPos.getIndex();
michael@0 2278 for (int32_t i = 0; i < fgStatusLength; ++i) {
michael@0 2279 status[i] = tmpStatus[i];
michael@0 2280 }
michael@0 2281 digits = tmpDigitList;
michael@0 2282 }
michael@0 2283 } else {
michael@0 2284 maxErrorPos = tmpPos.getErrorIndex();
michael@0 2285 }
michael@0 2286 // Then, parse against affix patterns.
michael@0 2287 // Those are currency patterns and currency plural patterns.
michael@0 2288 int32_t pos = -1;
michael@0 2289 const UHashElement* element = NULL;
michael@0 2290 while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
michael@0 2291 const UHashTok valueTok = element->value;
michael@0 2292 const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)valueTok.pointer;
michael@0 2293 UBool tmpStatus[fgStatusLength];
michael@0 2294 ParsePosition tmpPos(origPos);
michael@0 2295 DigitList tmpDigitList;
michael@0 2296
michael@0 2297 #ifdef FMT_DEBUG
michael@0 2298 debug("trying affix for currency..");
michael@0 2299 affixPtn->dump();
michael@0 2300 #endif
michael@0 2301
michael@0 2302 UBool result = subparse(text,
michael@0 2303 &affixPtn->negPrefixPatternForCurrency,
michael@0 2304 &affixPtn->negSuffixPatternForCurrency,
michael@0 2305 &affixPtn->posPrefixPatternForCurrency,
michael@0 2306 &affixPtn->posSuffixPatternForCurrency,
michael@0 2307 TRUE, affixPtn->patternType,
michael@0 2308 tmpPos, tmpDigitList, tmpStatus, currency);
michael@0 2309 if (result) {
michael@0 2310 found = true;
michael@0 2311 if (tmpPos.getIndex() > maxPosIndex) {
michael@0 2312 maxPosIndex = tmpPos.getIndex();
michael@0 2313 for (int32_t i = 0; i < fgStatusLength; ++i) {
michael@0 2314 status[i] = tmpStatus[i];
michael@0 2315 }
michael@0 2316 digits = tmpDigitList;
michael@0 2317 }
michael@0 2318 } else {
michael@0 2319 maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ?
michael@0 2320 tmpPos.getErrorIndex() : maxErrorPos;
michael@0 2321 }
michael@0 2322 }
michael@0 2323 // Finally, parse against simple affix to find the match.
michael@0 2324 // For example, in TestMonster suite,
michael@0 2325 // if the to-be-parsed text is "-\u00A40,00".
michael@0 2326 // complexAffixCompare will not find match,
michael@0 2327 // since there is no ISO code matches "\u00A4",
michael@0 2328 // and the parse stops at "\u00A4".
michael@0 2329 // We will just use simple affix comparison (look for exact match)
michael@0 2330 // to pass it.
michael@0 2331 //
michael@0 2332 // TODO: We should parse against simple affix first when
michael@0 2333 // output currency is not requested. After the complex currency
michael@0 2334 // parsing implementation was introduced, the default currency
michael@0 2335 // instance parsing slowed down because of the new code flow.
michael@0 2336 // I filed #10312 - Yoshito
michael@0 2337 UBool tmpStatus_2[fgStatusLength];
michael@0 2338 ParsePosition tmpPos_2(origPos);
michael@0 2339 DigitList tmpDigitList_2;
michael@0 2340
michael@0 2341 // Disable complex currency parsing and try it again.
michael@0 2342 UBool result = subparse(text,
michael@0 2343 &fNegativePrefix, &fNegativeSuffix,
michael@0 2344 &fPositivePrefix, &fPositiveSuffix,
michael@0 2345 FALSE /* disable complex currency parsing */, UCURR_SYMBOL_NAME,
michael@0 2346 tmpPos_2, tmpDigitList_2, tmpStatus_2,
michael@0 2347 currency);
michael@0 2348 if (result) {
michael@0 2349 if (tmpPos_2.getIndex() > maxPosIndex) {
michael@0 2350 maxPosIndex = tmpPos_2.getIndex();
michael@0 2351 for (int32_t i = 0; i < fgStatusLength; ++i) {
michael@0 2352 status[i] = tmpStatus_2[i];
michael@0 2353 }
michael@0 2354 digits = tmpDigitList_2;
michael@0 2355 }
michael@0 2356 found = true;
michael@0 2357 } else {
michael@0 2358 maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ?
michael@0 2359 tmpPos_2.getErrorIndex() : maxErrorPos;
michael@0 2360 }
michael@0 2361
michael@0 2362 if (!found) {
michael@0 2363 //parsePosition.setIndex(origPos);
michael@0 2364 parsePosition.setErrorIndex(maxErrorPos);
michael@0 2365 } else {
michael@0 2366 parsePosition.setIndex(maxPosIndex);
michael@0 2367 parsePosition.setErrorIndex(-1);
michael@0 2368 }
michael@0 2369 return found;
michael@0 2370 }
michael@0 2371
michael@0 2372
michael@0 2373 /**
michael@0 2374 * Parse the given text into a number. The text is parsed beginning at
michael@0 2375 * parsePosition, until an unparseable character is seen.
michael@0 2376 * @param text the string to parse.
michael@0 2377 * @param negPrefix negative prefix.
michael@0 2378 * @param negSuffix negative suffix.
michael@0 2379 * @param posPrefix positive prefix.
michael@0 2380 * @param posSuffix positive suffix.
michael@0 2381 * @param complexCurrencyParsing whether it is complex currency parsing or not.
michael@0 2382 * @param type the currency type to parse against, LONG_NAME only or not.
michael@0 2383 * @param parsePosition The position at which to being parsing. Upon
michael@0 2384 * return, the first unparsed character.
michael@0 2385 * @param digits the DigitList to set to the parsed value.
michael@0 2386 * @param status output param containing boolean status flags indicating
michael@0 2387 * whether the value was infinite and whether it was positive.
michael@0 2388 * @param currency return value for parsed currency, for generic
michael@0 2389 * currency parsing mode, or NULL for normal parsing. In generic
michael@0 2390 * currency parsing mode, any currency is parsed, not just the
michael@0 2391 * currency that this formatter is set to.
michael@0 2392 */
michael@0 2393 UBool DecimalFormat::subparse(const UnicodeString& text,
michael@0 2394 const UnicodeString* negPrefix,
michael@0 2395 const UnicodeString* negSuffix,
michael@0 2396 const UnicodeString* posPrefix,
michael@0 2397 const UnicodeString* posSuffix,
michael@0 2398 UBool complexCurrencyParsing,
michael@0 2399 int8_t type,
michael@0 2400 ParsePosition& parsePosition,
michael@0 2401 DigitList& digits, UBool* status,
michael@0 2402 UChar* currency) const
michael@0 2403 {
michael@0 2404 // The parsing process builds up the number as char string, in the neutral format that
michael@0 2405 // will be acceptable to the decNumber library, then at the end passes that string
michael@0 2406 // off for conversion to a decNumber.
michael@0 2407 UErrorCode err = U_ZERO_ERROR;
michael@0 2408 CharString parsedNum;
michael@0 2409 digits.setToZero();
michael@0 2410
michael@0 2411 int32_t position = parsePosition.getIndex();
michael@0 2412 int32_t oldStart = position;
michael@0 2413 int32_t textLength = text.length(); // One less pointer to follow
michael@0 2414 UBool strictParse = !isLenient();
michael@0 2415 UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
michael@0 2416 const UnicodeString *groupingString = &getConstSymbol(fCurrencySignCount == fgCurrencySignCountZero ?
michael@0 2417 DecimalFormatSymbols::kGroupingSeparatorSymbol : DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
michael@0 2418 UChar32 groupingChar = groupingString->char32At(0);
michael@0 2419 int32_t groupingStringLength = groupingString->length();
michael@0 2420 int32_t groupingCharLength = U16_LENGTH(groupingChar);
michael@0 2421 UBool groupingUsed = isGroupingUsed();
michael@0 2422 #ifdef FMT_DEBUG
michael@0 2423 UChar dbgbuf[300];
michael@0 2424 UnicodeString s(dbgbuf,0,300);;
michael@0 2425 s.append((UnicodeString)"PARSE \"").append(text.tempSubString(position)).append((UnicodeString)"\" " );
michael@0 2426 #define DBGAPPD(x) if(x) { s.append(UnicodeString(#x "=")); if(x->isEmpty()) { s.append(UnicodeString("<empty>")); } else { s.append(*x); } s.append(UnicodeString(" ")); } else { s.append(UnicodeString(#x "=NULL ")); }
michael@0 2427 DBGAPPD(negPrefix);
michael@0 2428 DBGAPPD(negSuffix);
michael@0 2429 DBGAPPD(posPrefix);
michael@0 2430 DBGAPPD(posSuffix);
michael@0 2431 debugout(s);
michael@0 2432 printf("currencyParsing=%d, fFormatWidth=%d, isParseIntegerOnly=%c text.length=%d negPrefLen=%d\n", currencyParsing, fFormatWidth, (isParseIntegerOnly())?'Y':'N', text.length(), negPrefix!=NULL?negPrefix->length():-1);
michael@0 2433 #endif
michael@0 2434
michael@0 2435 UBool fastParseOk = false; /* TRUE iff fast parse is OK */
michael@0 2436 // UBool fastParseHadDecimal = FALSE; /* true if fast parse saw a decimal point. */
michael@0 2437 const DecimalFormatInternal &data = internalData(fReserved);
michael@0 2438 if((data.fFastParseStatus==kFastpathYES) &&
michael@0 2439 fCurrencySignCount == fgCurrencySignCountZero &&
michael@0 2440 // (negPrefix!=NULL&&negPrefix->isEmpty()) ||
michael@0 2441 text.length()>0 &&
michael@0 2442 text.length()<32 &&
michael@0 2443 (posPrefix==NULL||posPrefix->isEmpty()) &&
michael@0 2444 (posSuffix==NULL||posSuffix->isEmpty()) &&
michael@0 2445 // (negPrefix==NULL||negPrefix->isEmpty()) &&
michael@0 2446 // (negSuffix==NULL||(negSuffix->isEmpty()) ) &&
michael@0 2447 TRUE) { // optimized path
michael@0 2448 int j=position;
michael@0 2449 int l=text.length();
michael@0 2450 int digitCount=0;
michael@0 2451 UChar32 ch = text.char32At(j);
michael@0 2452 const UnicodeString *decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
michael@0 2453 UChar32 decimalChar = 0;
michael@0 2454 UBool intOnly = FALSE;
michael@0 2455 UChar32 lookForGroup = (groupingUsed&&intOnly&&strictParse)?groupingChar:0;
michael@0 2456
michael@0 2457 int32_t decimalCount = decimalString->countChar32(0,3);
michael@0 2458 if(isParseIntegerOnly()) {
michael@0 2459 decimalChar = 0; // not allowed
michael@0 2460 intOnly = TRUE; // Don't look for decimals.
michael@0 2461 } else if(decimalCount==1) {
michael@0 2462 decimalChar = decimalString->char32At(0); // Look for this decimal
michael@0 2463 } else if(decimalCount==0) {
michael@0 2464 decimalChar=0; // NO decimal set
michael@0 2465 } else {
michael@0 2466 j=l+1;//Set counter to end of line, so that we break. Unknown decimal situation.
michael@0 2467 }
michael@0 2468
michael@0 2469 #ifdef FMT_DEBUG
michael@0 2470 printf("Preparing to do fastpath parse: decimalChar=U+%04X, groupingChar=U+%04X, first ch=U+%04X intOnly=%c strictParse=%c\n",
michael@0 2471 decimalChar, groupingChar, ch,
michael@0 2472 (intOnly)?'y':'n',
michael@0 2473 (strictParse)?'y':'n');
michael@0 2474 #endif
michael@0 2475 if(ch==0x002D) { // '-'
michael@0 2476 j=l+1;//=break - negative number.
michael@0 2477
michael@0 2478 /*
michael@0 2479 parsedNum.append('-',err);
michael@0 2480 j+=U16_LENGTH(ch);
michael@0 2481 if(j<l) ch = text.char32At(j);
michael@0 2482 */
michael@0 2483 } else {
michael@0 2484 parsedNum.append('+',err);
michael@0 2485 }
michael@0 2486 while(j<l) {
michael@0 2487 int32_t digit = ch - zero;
michael@0 2488 if(digit >=0 && digit <= 9) {
michael@0 2489 parsedNum.append((char)(digit + '0'), err);
michael@0 2490 if((digitCount>0) || digit!=0 || j==(l-1)) {
michael@0 2491 digitCount++;
michael@0 2492 }
michael@0 2493 } else if(ch == 0) { // break out
michael@0 2494 digitCount=-1;
michael@0 2495 break;
michael@0 2496 } else if(ch == decimalChar) {
michael@0 2497 parsedNum.append((char)('.'), err);
michael@0 2498 decimalChar=0; // no more decimals.
michael@0 2499 // fastParseHadDecimal=TRUE;
michael@0 2500 } else if(ch == lookForGroup) {
michael@0 2501 // ignore grouping char. No decimals, so it has to be an ignorable grouping sep
michael@0 2502 } else if(intOnly && (lookForGroup!=0) && !u_isdigit(ch)) {
michael@0 2503 // parsing integer only and can fall through
michael@0 2504 } else {
michael@0 2505 digitCount=-1; // fail - fall through to slow parse
michael@0 2506 break;
michael@0 2507 }
michael@0 2508 j+=U16_LENGTH(ch);
michael@0 2509 ch = text.char32At(j); // for next
michael@0 2510 }
michael@0 2511 if(
michael@0 2512 ((j==l)||intOnly) // end OR only parsing integer
michael@0 2513 && (digitCount>0)) { // and have at least one digit
michael@0 2514 #ifdef FMT_DEBUG
michael@0 2515 printf("PP -> %d, good = [%s] digitcount=%d, fGroupingSize=%d fGroupingSize2=%d!\n", j, parsedNum.data(), digitCount, fGroupingSize, fGroupingSize2);
michael@0 2516 #endif
michael@0 2517 fastParseOk=true; // Fast parse OK!
michael@0 2518
michael@0 2519 #ifdef SKIP_OPT
michael@0 2520 debug("SKIP_OPT");
michael@0 2521 /* for testing, try it the slow way. also */
michael@0 2522 fastParseOk=false;
michael@0 2523 parsedNum.clear();
michael@0 2524 #else
michael@0 2525 parsePosition.setIndex(position=j);
michael@0 2526 status[fgStatusInfinite]=false;
michael@0 2527 #endif
michael@0 2528 } else {
michael@0 2529 // was not OK. reset, retry
michael@0 2530 #ifdef FMT_DEBUG
michael@0 2531 printf("Fall through: j=%d, l=%d, digitCount=%d\n", j, l, digitCount);
michael@0 2532 #endif
michael@0 2533 parsedNum.clear();
michael@0 2534 }
michael@0 2535 } else {
michael@0 2536 #ifdef FMT_DEBUG
michael@0 2537 printf("Could not fastpath parse. ");
michael@0 2538 printf("fFormatWidth=%d ", fFormatWidth);
michael@0 2539 printf("text.length()=%d ", text.length());
michael@0 2540 printf("posPrefix=%p posSuffix=%p ", posPrefix, posSuffix);
michael@0 2541
michael@0 2542 printf("\n");
michael@0 2543 #endif
michael@0 2544 }
michael@0 2545
michael@0 2546 if(!fastParseOk
michael@0 2547 #if UCONFIG_HAVE_PARSEALLINPUT
michael@0 2548 && fParseAllInput!=UNUM_YES
michael@0 2549 #endif
michael@0 2550 )
michael@0 2551 {
michael@0 2552 // Match padding before prefix
michael@0 2553 if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) {
michael@0 2554 position = skipPadding(text, position);
michael@0 2555 }
michael@0 2556
michael@0 2557 // Match positive and negative prefixes; prefer longest match.
michael@0 2558 int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, complexCurrencyParsing, type, currency);
michael@0 2559 int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix, complexCurrencyParsing, type, currency);
michael@0 2560 if (posMatch >= 0 && negMatch >= 0) {
michael@0 2561 if (posMatch > negMatch) {
michael@0 2562 negMatch = -1;
michael@0 2563 } else if (negMatch > posMatch) {
michael@0 2564 posMatch = -1;
michael@0 2565 }
michael@0 2566 }
michael@0 2567 if (posMatch >= 0) {
michael@0 2568 position += posMatch;
michael@0 2569 parsedNum.append('+', err);
michael@0 2570 } else if (negMatch >= 0) {
michael@0 2571 position += negMatch;
michael@0 2572 parsedNum.append('-', err);
michael@0 2573 } else if (strictParse){
michael@0 2574 parsePosition.setErrorIndex(position);
michael@0 2575 return FALSE;
michael@0 2576 } else {
michael@0 2577 // Temporary set positive. This might be changed after checking suffix
michael@0 2578 parsedNum.append('+', err);
michael@0 2579 }
michael@0 2580
michael@0 2581 // Match padding before prefix
michael@0 2582 if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) {
michael@0 2583 position = skipPadding(text, position);
michael@0 2584 }
michael@0 2585
michael@0 2586 if (! strictParse) {
michael@0 2587 position = skipUWhiteSpace(text, position);
michael@0 2588 }
michael@0 2589
michael@0 2590 // process digits or Inf, find decimal position
michael@0 2591 const UnicodeString *inf = &getConstSymbol(DecimalFormatSymbols::kInfinitySymbol);
michael@0 2592 int32_t infLen = (text.compare(position, inf->length(), *inf)
michael@0 2593 ? 0 : inf->length());
michael@0 2594 position += infLen; // infLen is non-zero when it does equal to infinity
michael@0 2595 status[fgStatusInfinite] = infLen != 0;
michael@0 2596
michael@0 2597 if (infLen != 0) {
michael@0 2598 parsedNum.append("Infinity", err);
michael@0 2599 } else {
michael@0 2600 // We now have a string of digits, possibly with grouping symbols,
michael@0 2601 // and decimal points. We want to process these into a DigitList.
michael@0 2602 // We don't want to put a bunch of leading zeros into the DigitList
michael@0 2603 // though, so we keep track of the location of the decimal point,
michael@0 2604 // put only significant digits into the DigitList, and adjust the
michael@0 2605 // exponent as needed.
michael@0 2606
michael@0 2607
michael@0 2608 UBool strictFail = FALSE; // did we exit with a strict parse failure?
michael@0 2609 int32_t lastGroup = -1; // where did we last see a grouping separator?
michael@0 2610 int32_t digitStart = position;
michael@0 2611 int32_t gs2 = fGroupingSize2 == 0 ? fGroupingSize : fGroupingSize2;
michael@0 2612
michael@0 2613 const UnicodeString *decimalString;
michael@0 2614 if (fCurrencySignCount != fgCurrencySignCountZero) {
michael@0 2615 decimalString = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
michael@0 2616 } else {
michael@0 2617 decimalString = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
michael@0 2618 }
michael@0 2619 UChar32 decimalChar = decimalString->char32At(0);
michael@0 2620 int32_t decimalStringLength = decimalString->length();
michael@0 2621 int32_t decimalCharLength = U16_LENGTH(decimalChar);
michael@0 2622
michael@0 2623 UBool sawDecimal = FALSE;
michael@0 2624 UChar32 sawDecimalChar = 0xFFFF;
michael@0 2625 UBool sawGrouping = FALSE;
michael@0 2626 UChar32 sawGroupingChar = 0xFFFF;
michael@0 2627 UBool sawDigit = FALSE;
michael@0 2628 int32_t backup = -1;
michael@0 2629 int32_t digit;
michael@0 2630
michael@0 2631 // equivalent grouping and decimal support
michael@0 2632 const UnicodeSet *decimalSet = NULL;
michael@0 2633 const UnicodeSet *groupingSet = NULL;
michael@0 2634
michael@0 2635 if (decimalCharLength == decimalStringLength) {
michael@0 2636 decimalSet = DecimalFormatStaticSets::getSimilarDecimals(decimalChar, strictParse);
michael@0 2637 }
michael@0 2638
michael@0 2639 if (groupingCharLength == groupingStringLength) {
michael@0 2640 if (strictParse) {
michael@0 2641 groupingSet = fStaticSets->fStrictDefaultGroupingSeparators;
michael@0 2642 } else {
michael@0 2643 groupingSet = fStaticSets->fDefaultGroupingSeparators;
michael@0 2644 }
michael@0 2645 }
michael@0 2646
michael@0 2647 // We need to test groupingChar and decimalChar separately from groupingSet and decimalSet, if the sets are even initialized.
michael@0 2648 // If sawDecimal is TRUE, only consider sawDecimalChar and NOT decimalSet
michael@0 2649 // If a character matches decimalSet, don't consider it to be a member of the groupingSet.
michael@0 2650
michael@0 2651 // We have to track digitCount ourselves, because digits.fCount will
michael@0 2652 // pin when the maximum allowable digits is reached.
michael@0 2653 int32_t digitCount = 0;
michael@0 2654 int32_t integerDigitCount = 0;
michael@0 2655
michael@0 2656 for (; position < textLength; )
michael@0 2657 {
michael@0 2658 UChar32 ch = text.char32At(position);
michael@0 2659
michael@0 2660 /* We recognize all digit ranges, not only the Latin digit range
michael@0 2661 * '0'..'9'. We do so by using the Character.digit() method,
michael@0 2662 * which converts a valid Unicode digit to the range 0..9.
michael@0 2663 *
michael@0 2664 * The character 'ch' may be a digit. If so, place its value
michael@0 2665 * from 0 to 9 in 'digit'. First try using the locale digit,
michael@0 2666 * which may or MAY NOT be a standard Unicode digit range. If
michael@0 2667 * this fails, try using the standard Unicode digit ranges by
michael@0 2668 * calling Character.digit(). If this also fails, digit will
michael@0 2669 * have a value outside the range 0..9.
michael@0 2670 */
michael@0 2671 digit = ch - zero;
michael@0 2672 if (digit < 0 || digit > 9)
michael@0 2673 {
michael@0 2674 digit = u_charDigitValue(ch);
michael@0 2675 }
michael@0 2676
michael@0 2677 // As a last resort, look through the localized digits if the zero digit
michael@0 2678 // is not a "standard" Unicode digit.
michael@0 2679 if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) {
michael@0 2680 digit = 0;
michael@0 2681 if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kZeroDigitSymbol)).char32At(0) == ch ) {
michael@0 2682 break;
michael@0 2683 }
michael@0 2684 for (digit = 1 ; digit < 10 ; digit++ ) {
michael@0 2685 if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) {
michael@0 2686 break;
michael@0 2687 }
michael@0 2688 }
michael@0 2689 }
michael@0 2690
michael@0 2691 if (digit >= 0 && digit <= 9)
michael@0 2692 {
michael@0 2693 if (strictParse && backup != -1) {
michael@0 2694 // comma followed by digit, so group before comma is a
michael@0 2695 // secondary group. If there was a group separator
michael@0 2696 // before that, the group must == the secondary group
michael@0 2697 // length, else it can be <= the the secondary group
michael@0 2698 // length.
michael@0 2699 if ((lastGroup != -1 && backup - lastGroup - 1 != gs2) ||
michael@0 2700 (lastGroup == -1 && position - digitStart - 1 > gs2)) {
michael@0 2701 strictFail = TRUE;
michael@0 2702 break;
michael@0 2703 }
michael@0 2704
michael@0 2705 lastGroup = backup;
michael@0 2706 }
michael@0 2707
michael@0 2708 // Cancel out backup setting (see grouping handler below)
michael@0 2709 backup = -1;
michael@0 2710 sawDigit = TRUE;
michael@0 2711
michael@0 2712 // Note: this will append leading zeros
michael@0 2713 parsedNum.append((char)(digit + '0'), err);
michael@0 2714
michael@0 2715 // count any digit that's not a leading zero
michael@0 2716 if (digit > 0 || digitCount > 0 || sawDecimal) {
michael@0 2717 digitCount += 1;
michael@0 2718
michael@0 2719 // count any integer digit that's not a leading zero
michael@0 2720 if (! sawDecimal) {
michael@0 2721 integerDigitCount += 1;
michael@0 2722 }
michael@0 2723 }
michael@0 2724
michael@0 2725 position += U16_LENGTH(ch);
michael@0 2726 }
michael@0 2727 else if (groupingStringLength > 0 &&
michael@0 2728 matchGrouping(groupingChar, sawGrouping, sawGroupingChar, groupingSet,
michael@0 2729 decimalChar, decimalSet,
michael@0 2730 ch) && groupingUsed)
michael@0 2731 {
michael@0 2732 if (sawDecimal) {
michael@0 2733 break;
michael@0 2734 }
michael@0 2735
michael@0 2736 if (strictParse) {
michael@0 2737 if ((!sawDigit || backup != -1)) {
michael@0 2738 // leading group, or two group separators in a row
michael@0 2739 strictFail = TRUE;
michael@0 2740 break;
michael@0 2741 }
michael@0 2742 }
michael@0 2743
michael@0 2744 // Ignore grouping characters, if we are using them, but require
michael@0 2745 // that they be followed by a digit. Otherwise we backup and
michael@0 2746 // reprocess them.
michael@0 2747 backup = position;
michael@0 2748 position += groupingStringLength;
michael@0 2749 sawGrouping=TRUE;
michael@0 2750 // Once we see a grouping character, we only accept that grouping character from then on.
michael@0 2751 sawGroupingChar=ch;
michael@0 2752 }
michael@0 2753 else if (matchDecimal(decimalChar,sawDecimal,sawDecimalChar, decimalSet, ch))
michael@0 2754 {
michael@0 2755 if (strictParse) {
michael@0 2756 if (backup != -1 ||
michael@0 2757 (lastGroup != -1 && position - lastGroup != fGroupingSize + 1)) {
michael@0 2758 strictFail = TRUE;
michael@0 2759 break;
michael@0 2760 }
michael@0 2761 }
michael@0 2762
michael@0 2763 // If we're only parsing integers, or if we ALREADY saw the
michael@0 2764 // decimal, then don't parse this one.
michael@0 2765 if (isParseIntegerOnly() || sawDecimal) {
michael@0 2766 break;
michael@0 2767 }
michael@0 2768
michael@0 2769 parsedNum.append('.', err);
michael@0 2770 position += decimalStringLength;
michael@0 2771 sawDecimal = TRUE;
michael@0 2772 // Once we see a decimal character, we only accept that decimal character from then on.
michael@0 2773 sawDecimalChar=ch;
michael@0 2774 // decimalSet is considered to consist of (ch,ch)
michael@0 2775 }
michael@0 2776 else {
michael@0 2777
michael@0 2778 if(!fBoolFlags.contains(UNUM_PARSE_NO_EXPONENT) || // don't parse if this is set unless..
michael@0 2779 isScientificNotation()) { // .. it's an exponent format - ignore setting and parse anyways
michael@0 2780 const UnicodeString *tmp;
michael@0 2781 tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
michael@0 2782 // TODO: CASE
michael@0 2783 if (!text.caseCompare(position, tmp->length(), *tmp, U_FOLD_CASE_DEFAULT)) // error code is set below if !sawDigit
michael@0 2784 {
michael@0 2785 // Parse sign, if present
michael@0 2786 int32_t pos = position + tmp->length();
michael@0 2787 char exponentSign = '+';
michael@0 2788
michael@0 2789 if (pos < textLength)
michael@0 2790 {
michael@0 2791 tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
michael@0 2792 if (!text.compare(pos, tmp->length(), *tmp))
michael@0 2793 {
michael@0 2794 pos += tmp->length();
michael@0 2795 }
michael@0 2796 else {
michael@0 2797 tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
michael@0 2798 if (!text.compare(pos, tmp->length(), *tmp))
michael@0 2799 {
michael@0 2800 exponentSign = '-';
michael@0 2801 pos += tmp->length();
michael@0 2802 }
michael@0 2803 }
michael@0 2804 }
michael@0 2805
michael@0 2806 UBool sawExponentDigit = FALSE;
michael@0 2807 while (pos < textLength) {
michael@0 2808 ch = text[(int32_t)pos];
michael@0 2809 digit = ch - zero;
michael@0 2810
michael@0 2811 if (digit < 0 || digit > 9) {
michael@0 2812 digit = u_charDigitValue(ch);
michael@0 2813 }
michael@0 2814 if (0 <= digit && digit <= 9) {
michael@0 2815 if (!sawExponentDigit) {
michael@0 2816 parsedNum.append('E', err);
michael@0 2817 parsedNum.append(exponentSign, err);
michael@0 2818 sawExponentDigit = TRUE;
michael@0 2819 }
michael@0 2820 ++pos;
michael@0 2821 parsedNum.append((char)(digit + '0'), err);
michael@0 2822 } else {
michael@0 2823 break;
michael@0 2824 }
michael@0 2825 }
michael@0 2826
michael@0 2827 if (sawExponentDigit) {
michael@0 2828 position = pos; // Advance past the exponent
michael@0 2829 }
michael@0 2830
michael@0 2831 break; // Whether we fail or succeed, we exit this loop
michael@0 2832 } else {
michael@0 2833 break;
michael@0 2834 }
michael@0 2835 } else { // not parsing exponent
michael@0 2836 break;
michael@0 2837 }
michael@0 2838 }
michael@0 2839 }
michael@0 2840
michael@0 2841 if (backup != -1)
michael@0 2842 {
michael@0 2843 position = backup;
michael@0 2844 }
michael@0 2845
michael@0 2846 if (strictParse && !sawDecimal) {
michael@0 2847 if (lastGroup != -1 && position - lastGroup != fGroupingSize + 1) {
michael@0 2848 strictFail = TRUE;
michael@0 2849 }
michael@0 2850 }
michael@0 2851
michael@0 2852 if (strictFail) {
michael@0 2853 // only set with strictParse and a grouping separator error
michael@0 2854
michael@0 2855 parsePosition.setIndex(oldStart);
michael@0 2856 parsePosition.setErrorIndex(position);
michael@0 2857 debug("strictFail!");
michael@0 2858 return FALSE;
michael@0 2859 }
michael@0 2860
michael@0 2861 // If there was no decimal point we have an integer
michael@0 2862
michael@0 2863 // If none of the text string was recognized. For example, parse
michael@0 2864 // "x" with pattern "#0.00" (return index and error index both 0)
michael@0 2865 // parse "$" with pattern "$#0.00". (return index 0 and error index
michael@0 2866 // 1).
michael@0 2867 if (!sawDigit && digitCount == 0) {
michael@0 2868 #ifdef FMT_DEBUG
michael@0 2869 debug("none of text rec");
michael@0 2870 printf("position=%d\n",position);
michael@0 2871 #endif
michael@0 2872 parsePosition.setIndex(oldStart);
michael@0 2873 parsePosition.setErrorIndex(oldStart);
michael@0 2874 return FALSE;
michael@0 2875 }
michael@0 2876 }
michael@0 2877
michael@0 2878 // Match padding before suffix
michael@0 2879 if (fFormatWidth > 0 && fPadPosition == kPadBeforeSuffix) {
michael@0 2880 position = skipPadding(text, position);
michael@0 2881 }
michael@0 2882
michael@0 2883 int32_t posSuffixMatch = -1, negSuffixMatch = -1;
michael@0 2884
michael@0 2885 // Match positive and negative suffixes; prefer longest match.
michael@0 2886 if (posMatch >= 0 || (!strictParse && negMatch < 0)) {
michael@0 2887 posSuffixMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, complexCurrencyParsing, type, currency);
michael@0 2888 }
michael@0 2889 if (negMatch >= 0) {
michael@0 2890 negSuffixMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, complexCurrencyParsing, type, currency);
michael@0 2891 }
michael@0 2892 if (posSuffixMatch >= 0 && negSuffixMatch >= 0) {
michael@0 2893 if (posSuffixMatch > negSuffixMatch) {
michael@0 2894 negSuffixMatch = -1;
michael@0 2895 } else if (negSuffixMatch > posSuffixMatch) {
michael@0 2896 posSuffixMatch = -1;
michael@0 2897 }
michael@0 2898 }
michael@0 2899
michael@0 2900 // Fail if neither or both
michael@0 2901 if (strictParse && ((posSuffixMatch >= 0) == (negSuffixMatch >= 0))) {
michael@0 2902 parsePosition.setErrorIndex(position);
michael@0 2903 debug("neither or both");
michael@0 2904 return FALSE;
michael@0 2905 }
michael@0 2906
michael@0 2907 position += (posSuffixMatch >= 0 ? posSuffixMatch : (negSuffixMatch >= 0 ? negSuffixMatch : 0));
michael@0 2908
michael@0 2909 // Match padding before suffix
michael@0 2910 if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) {
michael@0 2911 position = skipPadding(text, position);
michael@0 2912 }
michael@0 2913
michael@0 2914 parsePosition.setIndex(position);
michael@0 2915
michael@0 2916 parsedNum.data()[0] = (posSuffixMatch >= 0 || (!strictParse && negMatch < 0 && negSuffixMatch < 0)) ? '+' : '-';
michael@0 2917 #ifdef FMT_DEBUG
michael@0 2918 printf("PP -> %d, SLOW = [%s]! pp=%d, os=%d, err=%s\n", position, parsedNum.data(), parsePosition.getIndex(),oldStart,u_errorName(err));
michael@0 2919 #endif
michael@0 2920 } /* end SLOW parse */
michael@0 2921 if(parsePosition.getIndex() == oldStart)
michael@0 2922 {
michael@0 2923 #ifdef FMT_DEBUG
michael@0 2924 printf(" PP didnt move, err\n");
michael@0 2925 #endif
michael@0 2926 parsePosition.setErrorIndex(position);
michael@0 2927 return FALSE;
michael@0 2928 }
michael@0 2929 #if UCONFIG_HAVE_PARSEALLINPUT
michael@0 2930 else if (fParseAllInput==UNUM_YES&&parsePosition.getIndex()!=textLength)
michael@0 2931 {
michael@0 2932 #ifdef FMT_DEBUG
michael@0 2933 printf(" PP didnt consume all (UNUM_YES), err\n");
michael@0 2934 #endif
michael@0 2935 parsePosition.setErrorIndex(position);
michael@0 2936 return FALSE;
michael@0 2937 }
michael@0 2938 #endif
michael@0 2939 // uint32_t bits = (fastParseOk?kFastpathOk:0) |
michael@0 2940 // (fastParseHadDecimal?0:kNoDecimal);
michael@0 2941 //printf("FPOK=%d, FPHD=%d, bits=%08X\n", fastParseOk, fastParseHadDecimal, bits);
michael@0 2942 digits.set(parsedNum.toStringPiece(),
michael@0 2943 err,
michael@0 2944 0//bits
michael@0 2945 );
michael@0 2946
michael@0 2947 if (U_FAILURE(err)) {
michael@0 2948 #ifdef FMT_DEBUG
michael@0 2949 printf(" err setting %s\n", u_errorName(err));
michael@0 2950 #endif
michael@0 2951 parsePosition.setErrorIndex(position);
michael@0 2952 return FALSE;
michael@0 2953 }
michael@0 2954 return TRUE;
michael@0 2955 }
michael@0 2956
michael@0 2957 /**
michael@0 2958 * Starting at position, advance past a run of pad characters, if any.
michael@0 2959 * Return the index of the first character after position that is not a pad
michael@0 2960 * character. Result is >= position.
michael@0 2961 */
michael@0 2962 int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position) const {
michael@0 2963 int32_t padLen = U16_LENGTH(fPad);
michael@0 2964 while (position < text.length() &&
michael@0 2965 text.char32At(position) == fPad) {
michael@0 2966 position += padLen;
michael@0 2967 }
michael@0 2968 return position;
michael@0 2969 }
michael@0 2970
michael@0 2971 /**
michael@0 2972 * Return the length matched by the given affix, or -1 if none.
michael@0 2973 * Runs of white space in the affix, match runs of white space in
michael@0 2974 * the input. Pattern white space and input white space are
michael@0 2975 * determined differently; see code.
michael@0 2976 * @param text input text
michael@0 2977 * @param pos offset into input at which to begin matching
michael@0 2978 * @param isNegative
michael@0 2979 * @param isPrefix
michael@0 2980 * @param affixPat affix pattern used for currency affix comparison.
michael@0 2981 * @param complexCurrencyParsing whether it is currency parsing or not
michael@0 2982 * @param type the currency type to parse against, LONG_NAME only or not.
michael@0 2983 * @param currency return value for parsed currency, for generic
michael@0 2984 * currency parsing mode, or null for normal parsing. In generic
michael@0 2985 * currency parsing mode, any currency is parsed, not just the
michael@0 2986 * currency that this formatter is set to.
michael@0 2987 * @return length of input that matches, or -1 if match failure
michael@0 2988 */
michael@0 2989 int32_t DecimalFormat::compareAffix(const UnicodeString& text,
michael@0 2990 int32_t pos,
michael@0 2991 UBool isNegative,
michael@0 2992 UBool isPrefix,
michael@0 2993 const UnicodeString* affixPat,
michael@0 2994 UBool complexCurrencyParsing,
michael@0 2995 int8_t type,
michael@0 2996 UChar* currency) const
michael@0 2997 {
michael@0 2998 const UnicodeString *patternToCompare;
michael@0 2999 if (fCurrencyChoice != NULL || currency != NULL ||
michael@0 3000 (fCurrencySignCount != fgCurrencySignCountZero && complexCurrencyParsing)) {
michael@0 3001
michael@0 3002 if (affixPat != NULL) {
michael@0 3003 return compareComplexAffix(*affixPat, text, pos, type, currency);
michael@0 3004 }
michael@0 3005 }
michael@0 3006
michael@0 3007 if (isNegative) {
michael@0 3008 if (isPrefix) {
michael@0 3009 patternToCompare = &fNegativePrefix;
michael@0 3010 }
michael@0 3011 else {
michael@0 3012 patternToCompare = &fNegativeSuffix;
michael@0 3013 }
michael@0 3014 }
michael@0 3015 else {
michael@0 3016 if (isPrefix) {
michael@0 3017 patternToCompare = &fPositivePrefix;
michael@0 3018 }
michael@0 3019 else {
michael@0 3020 patternToCompare = &fPositiveSuffix;
michael@0 3021 }
michael@0 3022 }
michael@0 3023 return compareSimpleAffix(*patternToCompare, text, pos, isLenient());
michael@0 3024 }
michael@0 3025
michael@0 3026 UBool DecimalFormat::equalWithSignCompatibility(UChar32 lhs, UChar32 rhs) const {
michael@0 3027 if (lhs == rhs) {
michael@0 3028 return TRUE;
michael@0 3029 }
michael@0 3030 U_ASSERT(fStaticSets != NULL); // should already be loaded
michael@0 3031 const UnicodeSet *minusSigns = fStaticSets->fMinusSigns;
michael@0 3032 const UnicodeSet *plusSigns = fStaticSets->fPlusSigns;
michael@0 3033 return (minusSigns->contains(lhs) && minusSigns->contains(rhs)) ||
michael@0 3034 (plusSigns->contains(lhs) && plusSigns->contains(rhs));
michael@0 3035 }
michael@0 3036
michael@0 3037 // check for LRM 0x200E, RLM 0x200F, ALM 0x061C
michael@0 3038 #define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
michael@0 3039
michael@0 3040 #define TRIM_BUFLEN 32
michael@0 3041 UnicodeString& DecimalFormat::trimMarksFromAffix(const UnicodeString& affix, UnicodeString& trimmedAffix) {
michael@0 3042 UChar trimBuf[TRIM_BUFLEN];
michael@0 3043 int32_t affixLen = affix.length();
michael@0 3044 int32_t affixPos, trimLen = 0;
michael@0 3045
michael@0 3046 for (affixPos = 0; affixPos < affixLen; affixPos++) {
michael@0 3047 UChar c = affix.charAt(affixPos);
michael@0 3048 if (!IS_BIDI_MARK(c)) {
michael@0 3049 if (trimLen < TRIM_BUFLEN) {
michael@0 3050 trimBuf[trimLen++] = c;
michael@0 3051 } else {
michael@0 3052 trimLen = 0;
michael@0 3053 break;
michael@0 3054 }
michael@0 3055 }
michael@0 3056 }
michael@0 3057 return (trimLen > 0)? trimmedAffix.setTo(trimBuf, trimLen): trimmedAffix.setTo(affix);
michael@0 3058 }
michael@0 3059
michael@0 3060 /**
michael@0 3061 * Return the length matched by the given affix, or -1 if none.
michael@0 3062 * Runs of white space in the affix, match runs of white space in
michael@0 3063 * the input. Pattern white space and input white space are
michael@0 3064 * determined differently; see code.
michael@0 3065 * @param affix pattern string, taken as a literal
michael@0 3066 * @param input input text
michael@0 3067 * @param pos offset into input at which to begin matching
michael@0 3068 * @return length of input that matches, or -1 if match failure
michael@0 3069 */
michael@0 3070 int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix,
michael@0 3071 const UnicodeString& input,
michael@0 3072 int32_t pos,
michael@0 3073 UBool lenient) const {
michael@0 3074 int32_t start = pos;
michael@0 3075 UnicodeString trimmedAffix;
michael@0 3076 // For more efficiency we should keep lazily-created trimmed affixes around in
michael@0 3077 // instance variables instead of trimming each time they are used (the next step)
michael@0 3078 trimMarksFromAffix(affix, trimmedAffix);
michael@0 3079 UChar32 affixChar = trimmedAffix.char32At(0);
michael@0 3080 int32_t affixLength = trimmedAffix.length();
michael@0 3081 int32_t inputLength = input.length();
michael@0 3082 int32_t affixCharLength = U16_LENGTH(affixChar);
michael@0 3083 UnicodeSet *affixSet;
michael@0 3084 UErrorCode status = U_ZERO_ERROR;
michael@0 3085
michael@0 3086 U_ASSERT(fStaticSets != NULL); // should already be loaded
michael@0 3087
michael@0 3088 if (U_FAILURE(status)) {
michael@0 3089 return -1;
michael@0 3090 }
michael@0 3091 if (!lenient) {
michael@0 3092 affixSet = fStaticSets->fStrictDashEquivalents;
michael@0 3093
michael@0 3094 // If the trimmedAffix is exactly one character long and that character
michael@0 3095 // is in the dash set and the very next input character is also
michael@0 3096 // in the dash set, return a match.
michael@0 3097 if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
michael@0 3098 UChar32 ic = input.char32At(pos);
michael@0 3099 if (affixSet->contains(ic)) {
michael@0 3100 pos += U16_LENGTH(ic);
michael@0 3101 pos = skipBidiMarks(input, pos); // skip any trailing bidi marks
michael@0 3102 return pos - start;
michael@0 3103 }
michael@0 3104 }
michael@0 3105
michael@0 3106 for (int32_t i = 0; i < affixLength; ) {
michael@0 3107 UChar32 c = trimmedAffix.char32At(i);
michael@0 3108 int32_t len = U16_LENGTH(c);
michael@0 3109 if (PatternProps::isWhiteSpace(c)) {
michael@0 3110 // We may have a pattern like: \u200F \u0020
michael@0 3111 // and input text like: \u200F \u0020
michael@0 3112 // Note that U+200F and U+0020 are Pattern_White_Space but only
michael@0 3113 // U+0020 is UWhiteSpace. So we have to first do a direct
michael@0 3114 // match of the run of Pattern_White_Space in the pattern,
michael@0 3115 // then match any extra characters.
michael@0 3116 UBool literalMatch = FALSE;
michael@0 3117 while (pos < inputLength) {
michael@0 3118 UChar32 ic = input.char32At(pos);
michael@0 3119 if (ic == c) {
michael@0 3120 literalMatch = TRUE;
michael@0 3121 i += len;
michael@0 3122 pos += len;
michael@0 3123 if (i == affixLength) {
michael@0 3124 break;
michael@0 3125 }
michael@0 3126 c = trimmedAffix.char32At(i);
michael@0 3127 len = U16_LENGTH(c);
michael@0 3128 if (!PatternProps::isWhiteSpace(c)) {
michael@0 3129 break;
michael@0 3130 }
michael@0 3131 } else if (IS_BIDI_MARK(ic)) {
michael@0 3132 pos ++; // just skip over this input text
michael@0 3133 } else {
michael@0 3134 break;
michael@0 3135 }
michael@0 3136 }
michael@0 3137
michael@0 3138 // Advance over run in pattern
michael@0 3139 i = skipPatternWhiteSpace(trimmedAffix, i);
michael@0 3140
michael@0 3141 // Advance over run in input text
michael@0 3142 // Must see at least one white space char in input,
michael@0 3143 // unless we've already matched some characters literally.
michael@0 3144 int32_t s = pos;
michael@0 3145 pos = skipUWhiteSpace(input, pos);
michael@0 3146 if (pos == s && !literalMatch) {
michael@0 3147 return -1;
michael@0 3148 }
michael@0 3149
michael@0 3150 // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
michael@0 3151 // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
michael@0 3152 // is also in the trimmedAffix.
michael@0 3153 i = skipUWhiteSpace(trimmedAffix, i);
michael@0 3154 } else {
michael@0 3155 UBool match = FALSE;
michael@0 3156 while (pos < inputLength) {
michael@0 3157 UChar32 ic = input.char32At(pos);
michael@0 3158 if (!match && ic == c) {
michael@0 3159 i += len;
michael@0 3160 pos += len;
michael@0 3161 match = TRUE;
michael@0 3162 } else if (IS_BIDI_MARK(ic)) {
michael@0 3163 pos++; // just skip over this input text
michael@0 3164 } else {
michael@0 3165 break;
michael@0 3166 }
michael@0 3167 }
michael@0 3168 if (!match) {
michael@0 3169 return -1;
michael@0 3170 }
michael@0 3171 }
michael@0 3172 }
michael@0 3173 } else {
michael@0 3174 UBool match = FALSE;
michael@0 3175
michael@0 3176 affixSet = fStaticSets->fDashEquivalents;
michael@0 3177
michael@0 3178 if (affixCharLength == affixLength && affixSet->contains(affixChar)) {
michael@0 3179 pos = skipUWhiteSpaceAndMarks(input, pos);
michael@0 3180 UChar32 ic = input.char32At(pos);
michael@0 3181
michael@0 3182 if (affixSet->contains(ic)) {
michael@0 3183 pos += U16_LENGTH(ic);
michael@0 3184 pos = skipBidiMarks(input, pos);
michael@0 3185 return pos - start;
michael@0 3186 }
michael@0 3187 }
michael@0 3188
michael@0 3189 for (int32_t i = 0; i < affixLength; )
michael@0 3190 {
michael@0 3191 //i = skipRuleWhiteSpace(trimmedAffix, i);
michael@0 3192 i = skipUWhiteSpace(trimmedAffix, i);
michael@0 3193 pos = skipUWhiteSpaceAndMarks(input, pos);
michael@0 3194
michael@0 3195 if (i >= affixLength || pos >= inputLength) {
michael@0 3196 break;
michael@0 3197 }
michael@0 3198
michael@0 3199 UChar32 c = trimmedAffix.char32At(i);
michael@0 3200 UChar32 ic = input.char32At(pos);
michael@0 3201
michael@0 3202 if (!equalWithSignCompatibility(ic, c)) {
michael@0 3203 return -1;
michael@0 3204 }
michael@0 3205
michael@0 3206 match = TRUE;
michael@0 3207 i += U16_LENGTH(c);
michael@0 3208 pos += U16_LENGTH(ic);
michael@0 3209 pos = skipBidiMarks(input, pos);
michael@0 3210 }
michael@0 3211
michael@0 3212 if (affixLength > 0 && ! match) {
michael@0 3213 return -1;
michael@0 3214 }
michael@0 3215 }
michael@0 3216 return pos - start;
michael@0 3217 }
michael@0 3218
michael@0 3219 /**
michael@0 3220 * Skip over a run of zero or more Pattern_White_Space characters at
michael@0 3221 * pos in text.
michael@0 3222 */
michael@0 3223 int32_t DecimalFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) {
michael@0 3224 const UChar* s = text.getBuffer();
michael@0 3225 return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
michael@0 3226 }
michael@0 3227
michael@0 3228 /**
michael@0 3229 * Skip over a run of zero or more isUWhiteSpace() characters at pos
michael@0 3230 * in text.
michael@0 3231 */
michael@0 3232 int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) {
michael@0 3233 while (pos < text.length()) {
michael@0 3234 UChar32 c = text.char32At(pos);
michael@0 3235 if (!u_isUWhiteSpace(c)) {
michael@0 3236 break;
michael@0 3237 }
michael@0 3238 pos += U16_LENGTH(c);
michael@0 3239 }
michael@0 3240 return pos;
michael@0 3241 }
michael@0 3242
michael@0 3243 /**
michael@0 3244 * Skip over a run of zero or more isUWhiteSpace() characters or bidi marks at pos
michael@0 3245 * in text.
michael@0 3246 */
michael@0 3247 int32_t DecimalFormat::skipUWhiteSpaceAndMarks(const UnicodeString& text, int32_t pos) {
michael@0 3248 while (pos < text.length()) {
michael@0 3249 UChar32 c = text.char32At(pos);
michael@0 3250 if (!u_isUWhiteSpace(c) && !IS_BIDI_MARK(c)) { // u_isUWhiteSpace doesn't include LRM,RLM,ALM
michael@0 3251 break;
michael@0 3252 }
michael@0 3253 pos += U16_LENGTH(c);
michael@0 3254 }
michael@0 3255 return pos;
michael@0 3256 }
michael@0 3257
michael@0 3258 /**
michael@0 3259 * Skip over a run of zero or more bidi marks at pos in text.
michael@0 3260 */
michael@0 3261 int32_t DecimalFormat::skipBidiMarks(const UnicodeString& text, int32_t pos) {
michael@0 3262 while (pos < text.length()) {
michael@0 3263 UChar c = text.charAt(pos);
michael@0 3264 if (!IS_BIDI_MARK(c)) {
michael@0 3265 break;
michael@0 3266 }
michael@0 3267 pos++;
michael@0 3268 }
michael@0 3269 return pos;
michael@0 3270 }
michael@0 3271
michael@0 3272 /**
michael@0 3273 * Return the length matched by the given affix, or -1 if none.
michael@0 3274 * @param affixPat pattern string
michael@0 3275 * @param input input text
michael@0 3276 * @param pos offset into input at which to begin matching
michael@0 3277 * @param type the currency type to parse against, LONG_NAME only or not.
michael@0 3278 * @param currency return value for parsed currency, for generic
michael@0 3279 * currency parsing mode, or null for normal parsing. In generic
michael@0 3280 * currency parsing mode, any currency is parsed, not just the
michael@0 3281 * currency that this formatter is set to.
michael@0 3282 * @return length of input that matches, or -1 if match failure
michael@0 3283 */
michael@0 3284 int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat,
michael@0 3285 const UnicodeString& text,
michael@0 3286 int32_t pos,
michael@0 3287 int8_t type,
michael@0 3288 UChar* currency) const
michael@0 3289 {
michael@0 3290 int32_t start = pos;
michael@0 3291 U_ASSERT(currency != NULL ||
michael@0 3292 (fCurrencyChoice != NULL && *getCurrency() != 0) ||
michael@0 3293 fCurrencySignCount != fgCurrencySignCountZero);
michael@0 3294
michael@0 3295 for (int32_t i=0;
michael@0 3296 i<affixPat.length() && pos >= 0; ) {
michael@0 3297 UChar32 c = affixPat.char32At(i);
michael@0 3298 i += U16_LENGTH(c);
michael@0 3299
michael@0 3300 if (c == kQuote) {
michael@0 3301 U_ASSERT(i <= affixPat.length());
michael@0 3302 c = affixPat.char32At(i);
michael@0 3303 i += U16_LENGTH(c);
michael@0 3304
michael@0 3305 const UnicodeString* affix = NULL;
michael@0 3306
michael@0 3307 switch (c) {
michael@0 3308 case kCurrencySign: {
michael@0 3309 // since the currency names in choice format is saved
michael@0 3310 // the same way as other currency names,
michael@0 3311 // do not need to do currency choice parsing here.
michael@0 3312 // the general currency parsing parse against all names,
michael@0 3313 // including names in choice format.
michael@0 3314 UBool intl = i<affixPat.length() &&
michael@0 3315 affixPat.char32At(i) == kCurrencySign;
michael@0 3316 if (intl) {
michael@0 3317 ++i;
michael@0 3318 }
michael@0 3319 UBool plural = i<affixPat.length() &&
michael@0 3320 affixPat.char32At(i) == kCurrencySign;
michael@0 3321 if (plural) {
michael@0 3322 ++i;
michael@0 3323 intl = FALSE;
michael@0 3324 }
michael@0 3325 // Parse generic currency -- anything for which we
michael@0 3326 // have a display name, or any 3-letter ISO code.
michael@0 3327 // Try to parse display name for our locale; first
michael@0 3328 // determine our locale.
michael@0 3329 const char* loc = fCurrencyPluralInfo->getLocale().getName();
michael@0 3330 ParsePosition ppos(pos);
michael@0 3331 UChar curr[4];
michael@0 3332 UErrorCode ec = U_ZERO_ERROR;
michael@0 3333 // Delegate parse of display name => ISO code to Currency
michael@0 3334 uprv_parseCurrency(loc, text, ppos, type, curr, ec);
michael@0 3335
michael@0 3336 // If parse succeeds, populate currency[0]
michael@0 3337 if (U_SUCCESS(ec) && ppos.getIndex() != pos) {
michael@0 3338 if (currency) {
michael@0 3339 u_strcpy(currency, curr);
michael@0 3340 } else {
michael@0 3341 // The formatter is currency-style but the client has not requested
michael@0 3342 // the value of the parsed currency. In this case, if that value does
michael@0 3343 // not match the formatter's current value, then the parse fails.
michael@0 3344 UChar effectiveCurr[4];
michael@0 3345 getEffectiveCurrency(effectiveCurr, ec);
michael@0 3346 if ( U_FAILURE(ec) || u_strncmp(curr,effectiveCurr,4) != 0 ) {
michael@0 3347 pos = -1;
michael@0 3348 continue;
michael@0 3349 }
michael@0 3350 }
michael@0 3351 pos = ppos.getIndex();
michael@0 3352 } else if (!isLenient()){
michael@0 3353 pos = -1;
michael@0 3354 }
michael@0 3355 continue;
michael@0 3356 }
michael@0 3357 case kPatternPercent:
michael@0 3358 affix = &getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
michael@0 3359 break;
michael@0 3360 case kPatternPerMill:
michael@0 3361 affix = &getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
michael@0 3362 break;
michael@0 3363 case kPatternPlus:
michael@0 3364 affix = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
michael@0 3365 break;
michael@0 3366 case kPatternMinus:
michael@0 3367 affix = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
michael@0 3368 break;
michael@0 3369 default:
michael@0 3370 // fall through to affix!=0 test, which will fail
michael@0 3371 break;
michael@0 3372 }
michael@0 3373
michael@0 3374 if (affix != NULL) {
michael@0 3375 pos = match(text, pos, *affix);
michael@0 3376 continue;
michael@0 3377 }
michael@0 3378 }
michael@0 3379
michael@0 3380 pos = match(text, pos, c);
michael@0 3381 if (PatternProps::isWhiteSpace(c)) {
michael@0 3382 i = skipPatternWhiteSpace(affixPat, i);
michael@0 3383 }
michael@0 3384 }
michael@0 3385 return pos - start;
michael@0 3386 }
michael@0 3387
michael@0 3388 /**
michael@0 3389 * Match a single character at text[pos] and return the index of the
michael@0 3390 * next character upon success. Return -1 on failure. If
michael@0 3391 * ch is a Pattern_White_Space then match a run of white space in text.
michael@0 3392 */
michael@0 3393 int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch) {
michael@0 3394 if (PatternProps::isWhiteSpace(ch)) {
michael@0 3395 // Advance over run of white space in input text
michael@0 3396 // Must see at least one white space char in input
michael@0 3397 int32_t s = pos;
michael@0 3398 pos = skipPatternWhiteSpace(text, pos);
michael@0 3399 if (pos == s) {
michael@0 3400 return -1;
michael@0 3401 }
michael@0 3402 return pos;
michael@0 3403 }
michael@0 3404 return (pos >= 0 && text.char32At(pos) == ch) ?
michael@0 3405 (pos + U16_LENGTH(ch)) : -1;
michael@0 3406 }
michael@0 3407
michael@0 3408 /**
michael@0 3409 * Match a string at text[pos] and return the index of the next
michael@0 3410 * character upon success. Return -1 on failure. Match a run of
michael@0 3411 * white space in str with a run of white space in text.
michael@0 3412 */
michael@0 3413 int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const UnicodeString& str) {
michael@0 3414 for (int32_t i=0; i<str.length() && pos >= 0; ) {
michael@0 3415 UChar32 ch = str.char32At(i);
michael@0 3416 i += U16_LENGTH(ch);
michael@0 3417 if (PatternProps::isWhiteSpace(ch)) {
michael@0 3418 i = skipPatternWhiteSpace(str, i);
michael@0 3419 }
michael@0 3420 pos = match(text, pos, ch);
michael@0 3421 }
michael@0 3422 return pos;
michael@0 3423 }
michael@0 3424
michael@0 3425 UBool DecimalFormat::matchSymbol(const UnicodeString &text, int32_t position, int32_t length, const UnicodeString &symbol,
michael@0 3426 UnicodeSet *sset, UChar32 schar)
michael@0 3427 {
michael@0 3428 if (sset != NULL) {
michael@0 3429 return sset->contains(schar);
michael@0 3430 }
michael@0 3431
michael@0 3432 return text.compare(position, length, symbol) == 0;
michael@0 3433 }
michael@0 3434
michael@0 3435 UBool DecimalFormat::matchDecimal(UChar32 symbolChar,
michael@0 3436 UBool sawDecimal, UChar32 sawDecimalChar,
michael@0 3437 const UnicodeSet *sset, UChar32 schar) {
michael@0 3438 if(sawDecimal) {
michael@0 3439 return schar==sawDecimalChar;
michael@0 3440 } else if(schar==symbolChar) {
michael@0 3441 return TRUE;
michael@0 3442 } else if(sset!=NULL) {
michael@0 3443 return sset->contains(schar);
michael@0 3444 } else {
michael@0 3445 return FALSE;
michael@0 3446 }
michael@0 3447 }
michael@0 3448
michael@0 3449 UBool DecimalFormat::matchGrouping(UChar32 groupingChar,
michael@0 3450 UBool sawGrouping, UChar32 sawGroupingChar,
michael@0 3451 const UnicodeSet *sset,
michael@0 3452 UChar32 /*decimalChar*/, const UnicodeSet *decimalSet,
michael@0 3453 UChar32 schar) {
michael@0 3454 if(sawGrouping) {
michael@0 3455 return schar==sawGroupingChar; // previously found
michael@0 3456 } else if(schar==groupingChar) {
michael@0 3457 return TRUE; // char from symbols
michael@0 3458 } else if(sset!=NULL) {
michael@0 3459 return sset->contains(schar) && // in groupingSet but...
michael@0 3460 ((decimalSet==NULL) || !decimalSet->contains(schar)); // Exclude decimalSet from groupingSet
michael@0 3461 } else {
michael@0 3462 return FALSE;
michael@0 3463 }
michael@0 3464 }
michael@0 3465
michael@0 3466
michael@0 3467
michael@0 3468 //------------------------------------------------------------------------------
michael@0 3469 // Gets the pointer to the localized decimal format symbols
michael@0 3470
michael@0 3471 const DecimalFormatSymbols*
michael@0 3472 DecimalFormat::getDecimalFormatSymbols() const
michael@0 3473 {
michael@0 3474 return fSymbols;
michael@0 3475 }
michael@0 3476
michael@0 3477 //------------------------------------------------------------------------------
michael@0 3478 // De-owning the current localized symbols and adopt the new symbols.
michael@0 3479
michael@0 3480 void
michael@0 3481 DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt)
michael@0 3482 {
michael@0 3483 if (symbolsToAdopt == NULL) {
michael@0 3484 return; // do not allow caller to set fSymbols to NULL
michael@0 3485 }
michael@0 3486
michael@0 3487 UBool sameSymbols = FALSE;
michael@0 3488 if (fSymbols != NULL) {
michael@0 3489 sameSymbols = (UBool)(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) ==
michael@0 3490 symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) &&
michael@0 3491 getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) ==
michael@0 3492 symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
michael@0 3493 delete fSymbols;
michael@0 3494 }
michael@0 3495
michael@0 3496 fSymbols = symbolsToAdopt;
michael@0 3497 if (!sameSymbols) {
michael@0 3498 // If the currency symbols are the same, there is no need to recalculate.
michael@0 3499 setCurrencyForSymbols();
michael@0 3500 }
michael@0 3501 expandAffixes(NULL);
michael@0 3502 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3503 handleChanged();
michael@0 3504 #endif
michael@0 3505 }
michael@0 3506 //------------------------------------------------------------------------------
michael@0 3507 // Setting the symbols is equlivalent to adopting a newly created localized
michael@0 3508 // symbols.
michael@0 3509
michael@0 3510 void
michael@0 3511 DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols)
michael@0 3512 {
michael@0 3513 adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols));
michael@0 3514 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3515 handleChanged();
michael@0 3516 #endif
michael@0 3517 }
michael@0 3518
michael@0 3519
michael@0 3520 const CurrencyPluralInfo*
michael@0 3521 DecimalFormat::getCurrencyPluralInfo(void) const
michael@0 3522 {
michael@0 3523 return fCurrencyPluralInfo;
michael@0 3524 }
michael@0 3525
michael@0 3526
michael@0 3527 void
michael@0 3528 DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt)
michael@0 3529 {
michael@0 3530 if (toAdopt != NULL) {
michael@0 3531 delete fCurrencyPluralInfo;
michael@0 3532 fCurrencyPluralInfo = toAdopt;
michael@0 3533 // re-set currency affix patterns and currency affixes.
michael@0 3534 if (fCurrencySignCount != fgCurrencySignCountZero) {
michael@0 3535 UErrorCode status = U_ZERO_ERROR;
michael@0 3536 if (fAffixPatternsForCurrency) {
michael@0 3537 deleteHashForAffixPattern();
michael@0 3538 }
michael@0 3539 setupCurrencyAffixPatterns(status);
michael@0 3540 if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
michael@0 3541 // only setup the affixes of the plural pattern.
michael@0 3542 setupCurrencyAffixes(fFormatPattern, FALSE, TRUE, status);
michael@0 3543 }
michael@0 3544 }
michael@0 3545 }
michael@0 3546 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3547 handleChanged();
michael@0 3548 #endif
michael@0 3549 }
michael@0 3550
michael@0 3551 void
michael@0 3552 DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info)
michael@0 3553 {
michael@0 3554 adoptCurrencyPluralInfo(info.clone());
michael@0 3555 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3556 handleChanged();
michael@0 3557 #endif
michael@0 3558 }
michael@0 3559
michael@0 3560
michael@0 3561 /**
michael@0 3562 * Update the currency object to match the symbols. This method
michael@0 3563 * is used only when the caller has passed in a symbols object
michael@0 3564 * that may not be the default object for its locale.
michael@0 3565 */
michael@0 3566 void
michael@0 3567 DecimalFormat::setCurrencyForSymbols() {
michael@0 3568 /*Bug 4212072
michael@0 3569 Update the affix strings accroding to symbols in order to keep
michael@0 3570 the affix strings up to date.
michael@0 3571 [Richard/GCL]
michael@0 3572 */
michael@0 3573
michael@0 3574 // With the introduction of the Currency object, the currency
michael@0 3575 // symbols in the DFS object are ignored. For backward
michael@0 3576 // compatibility, we check any explicitly set DFS object. If it
michael@0 3577 // is a default symbols object for its locale, we change the
michael@0 3578 // currency object to one for that locale. If it is custom,
michael@0 3579 // we set the currency to null.
michael@0 3580 UErrorCode ec = U_ZERO_ERROR;
michael@0 3581 const UChar* c = NULL;
michael@0 3582 const char* loc = fSymbols->getLocale().getName();
michael@0 3583 UChar intlCurrencySymbol[4];
michael@0 3584 ucurr_forLocale(loc, intlCurrencySymbol, 4, &ec);
michael@0 3585 UnicodeString currencySymbol;
michael@0 3586
michael@0 3587 uprv_getStaticCurrencyName(intlCurrencySymbol, loc, currencySymbol, ec);
michael@0 3588 if (U_SUCCESS(ec)
michael@0 3589 && getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) == currencySymbol
michael@0 3590 && getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) == UnicodeString(intlCurrencySymbol))
michael@0 3591 {
michael@0 3592 // Trap an error in mapping locale to currency. If we can't
michael@0 3593 // map, then don't fail and set the currency to "".
michael@0 3594 c = intlCurrencySymbol;
michael@0 3595 }
michael@0 3596 ec = U_ZERO_ERROR; // reset local error code!
michael@0 3597 setCurrencyInternally(c, ec);
michael@0 3598 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3599 handleChanged();
michael@0 3600 #endif
michael@0 3601 }
michael@0 3602
michael@0 3603
michael@0 3604 //------------------------------------------------------------------------------
michael@0 3605 // Gets the positive prefix of the number pattern.
michael@0 3606
michael@0 3607 UnicodeString&
michael@0 3608 DecimalFormat::getPositivePrefix(UnicodeString& result) const
michael@0 3609 {
michael@0 3610 result = fPositivePrefix;
michael@0 3611 return result;
michael@0 3612 }
michael@0 3613
michael@0 3614 //------------------------------------------------------------------------------
michael@0 3615 // Sets the positive prefix of the number pattern.
michael@0 3616
michael@0 3617 void
michael@0 3618 DecimalFormat::setPositivePrefix(const UnicodeString& newValue)
michael@0 3619 {
michael@0 3620 fPositivePrefix = newValue;
michael@0 3621 delete fPosPrefixPattern;
michael@0 3622 fPosPrefixPattern = 0;
michael@0 3623 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3624 handleChanged();
michael@0 3625 #endif
michael@0 3626 }
michael@0 3627
michael@0 3628 //------------------------------------------------------------------------------
michael@0 3629 // Gets the negative prefix of the number pattern.
michael@0 3630
michael@0 3631 UnicodeString&
michael@0 3632 DecimalFormat::getNegativePrefix(UnicodeString& result) const
michael@0 3633 {
michael@0 3634 result = fNegativePrefix;
michael@0 3635 return result;
michael@0 3636 }
michael@0 3637
michael@0 3638 //------------------------------------------------------------------------------
michael@0 3639 // Gets the negative prefix of the number pattern.
michael@0 3640
michael@0 3641 void
michael@0 3642 DecimalFormat::setNegativePrefix(const UnicodeString& newValue)
michael@0 3643 {
michael@0 3644 fNegativePrefix = newValue;
michael@0 3645 delete fNegPrefixPattern;
michael@0 3646 fNegPrefixPattern = 0;
michael@0 3647 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3648 handleChanged();
michael@0 3649 #endif
michael@0 3650 }
michael@0 3651
michael@0 3652 //------------------------------------------------------------------------------
michael@0 3653 // Gets the positive suffix of the number pattern.
michael@0 3654
michael@0 3655 UnicodeString&
michael@0 3656 DecimalFormat::getPositiveSuffix(UnicodeString& result) const
michael@0 3657 {
michael@0 3658 result = fPositiveSuffix;
michael@0 3659 return result;
michael@0 3660 }
michael@0 3661
michael@0 3662 //------------------------------------------------------------------------------
michael@0 3663 // Sets the positive suffix of the number pattern.
michael@0 3664
michael@0 3665 void
michael@0 3666 DecimalFormat::setPositiveSuffix(const UnicodeString& newValue)
michael@0 3667 {
michael@0 3668 fPositiveSuffix = newValue;
michael@0 3669 delete fPosSuffixPattern;
michael@0 3670 fPosSuffixPattern = 0;
michael@0 3671 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3672 handleChanged();
michael@0 3673 #endif
michael@0 3674 }
michael@0 3675
michael@0 3676 //------------------------------------------------------------------------------
michael@0 3677 // Gets the negative suffix of the number pattern.
michael@0 3678
michael@0 3679 UnicodeString&
michael@0 3680 DecimalFormat::getNegativeSuffix(UnicodeString& result) const
michael@0 3681 {
michael@0 3682 result = fNegativeSuffix;
michael@0 3683 return result;
michael@0 3684 }
michael@0 3685
michael@0 3686 //------------------------------------------------------------------------------
michael@0 3687 // Sets the negative suffix of the number pattern.
michael@0 3688
michael@0 3689 void
michael@0 3690 DecimalFormat::setNegativeSuffix(const UnicodeString& newValue)
michael@0 3691 {
michael@0 3692 fNegativeSuffix = newValue;
michael@0 3693 delete fNegSuffixPattern;
michael@0 3694 fNegSuffixPattern = 0;
michael@0 3695 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3696 handleChanged();
michael@0 3697 #endif
michael@0 3698 }
michael@0 3699
michael@0 3700 //------------------------------------------------------------------------------
michael@0 3701 // Gets the multiplier of the number pattern.
michael@0 3702 // Multipliers are stored as decimal numbers (DigitLists) because that
michael@0 3703 // is the most convenient for muliplying or dividing the numbers to be formatted.
michael@0 3704 // A NULL multiplier implies one, and the scaling operations are skipped.
michael@0 3705
michael@0 3706 int32_t
michael@0 3707 DecimalFormat::getMultiplier() const
michael@0 3708 {
michael@0 3709 if (fMultiplier == NULL) {
michael@0 3710 return 1;
michael@0 3711 } else {
michael@0 3712 return fMultiplier->getLong();
michael@0 3713 }
michael@0 3714 }
michael@0 3715
michael@0 3716 //------------------------------------------------------------------------------
michael@0 3717 // Sets the multiplier of the number pattern.
michael@0 3718 void
michael@0 3719 DecimalFormat::setMultiplier(int32_t newValue)
michael@0 3720 {
michael@0 3721 // if (newValue == 0) {
michael@0 3722 // throw new IllegalArgumentException("Bad multiplier: " + newValue);
michael@0 3723 // }
michael@0 3724 if (newValue == 0) {
michael@0 3725 newValue = 1; // one being the benign default value for a multiplier.
michael@0 3726 }
michael@0 3727 if (newValue == 1) {
michael@0 3728 delete fMultiplier;
michael@0 3729 fMultiplier = NULL;
michael@0 3730 } else {
michael@0 3731 if (fMultiplier == NULL) {
michael@0 3732 fMultiplier = new DigitList;
michael@0 3733 }
michael@0 3734 if (fMultiplier != NULL) {
michael@0 3735 fMultiplier->set(newValue);
michael@0 3736 }
michael@0 3737 }
michael@0 3738 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3739 handleChanged();
michael@0 3740 #endif
michael@0 3741 }
michael@0 3742
michael@0 3743 /**
michael@0 3744 * Get the rounding increment.
michael@0 3745 * @return A positive rounding increment, or 0.0 if rounding
michael@0 3746 * is not in effect.
michael@0 3747 * @see #setRoundingIncrement
michael@0 3748 * @see #getRoundingMode
michael@0 3749 * @see #setRoundingMode
michael@0 3750 */
michael@0 3751 double DecimalFormat::getRoundingIncrement() const {
michael@0 3752 if (fRoundingIncrement == NULL) {
michael@0 3753 return 0.0;
michael@0 3754 } else {
michael@0 3755 return fRoundingIncrement->getDouble();
michael@0 3756 }
michael@0 3757 }
michael@0 3758
michael@0 3759 /**
michael@0 3760 * Set the rounding increment. This method also controls whether
michael@0 3761 * rounding is enabled.
michael@0 3762 * @param newValue A positive rounding increment, or 0.0 to disable rounding.
michael@0 3763 * Negative increments are equivalent to 0.0.
michael@0 3764 * @see #getRoundingIncrement
michael@0 3765 * @see #getRoundingMode
michael@0 3766 * @see #setRoundingMode
michael@0 3767 */
michael@0 3768 void DecimalFormat::setRoundingIncrement(double newValue) {
michael@0 3769 if (newValue > 0.0) {
michael@0 3770 if (fRoundingIncrement == NULL) {
michael@0 3771 fRoundingIncrement = new DigitList();
michael@0 3772 }
michael@0 3773 if (fRoundingIncrement != NULL) {
michael@0 3774 fRoundingIncrement->set(newValue);
michael@0 3775 return;
michael@0 3776 }
michael@0 3777 }
michael@0 3778 // These statements are executed if newValue is less than 0.0
michael@0 3779 // or fRoundingIncrement could not be created.
michael@0 3780 delete fRoundingIncrement;
michael@0 3781 fRoundingIncrement = NULL;
michael@0 3782 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3783 handleChanged();
michael@0 3784 #endif
michael@0 3785 }
michael@0 3786
michael@0 3787 /**
michael@0 3788 * Get the rounding mode.
michael@0 3789 * @return A rounding mode
michael@0 3790 * @see #setRoundingIncrement
michael@0 3791 * @see #getRoundingIncrement
michael@0 3792 * @see #setRoundingMode
michael@0 3793 */
michael@0 3794 DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const {
michael@0 3795 return fRoundingMode;
michael@0 3796 }
michael@0 3797
michael@0 3798 /**
michael@0 3799 * Set the rounding mode. This has no effect unless the rounding
michael@0 3800 * increment is greater than zero.
michael@0 3801 * @param roundingMode A rounding mode
michael@0 3802 * @see #setRoundingIncrement
michael@0 3803 * @see #getRoundingIncrement
michael@0 3804 * @see #getRoundingMode
michael@0 3805 */
michael@0 3806 void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {
michael@0 3807 fRoundingMode = roundingMode;
michael@0 3808 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3809 handleChanged();
michael@0 3810 #endif
michael@0 3811 }
michael@0 3812
michael@0 3813 /**
michael@0 3814 * Get the width to which the output of <code>format()</code> is padded.
michael@0 3815 * @return the format width, or zero if no padding is in effect
michael@0 3816 * @see #setFormatWidth
michael@0 3817 * @see #getPadCharacter
michael@0 3818 * @see #setPadCharacter
michael@0 3819 * @see #getPadPosition
michael@0 3820 * @see #setPadPosition
michael@0 3821 */
michael@0 3822 int32_t DecimalFormat::getFormatWidth() const {
michael@0 3823 return fFormatWidth;
michael@0 3824 }
michael@0 3825
michael@0 3826 /**
michael@0 3827 * Set the width to which the output of <code>format()</code> is padded.
michael@0 3828 * This method also controls whether padding is enabled.
michael@0 3829 * @param width the width to which to pad the result of
michael@0 3830 * <code>format()</code>, or zero to disable padding. A negative
michael@0 3831 * width is equivalent to 0.
michael@0 3832 * @see #getFormatWidth
michael@0 3833 * @see #getPadCharacter
michael@0 3834 * @see #setPadCharacter
michael@0 3835 * @see #getPadPosition
michael@0 3836 * @see #setPadPosition
michael@0 3837 */
michael@0 3838 void DecimalFormat::setFormatWidth(int32_t width) {
michael@0 3839 fFormatWidth = (width > 0) ? width : 0;
michael@0 3840 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3841 handleChanged();
michael@0 3842 #endif
michael@0 3843 }
michael@0 3844
michael@0 3845 UnicodeString DecimalFormat::getPadCharacterString() const {
michael@0 3846 return UnicodeString(fPad);
michael@0 3847 }
michael@0 3848
michael@0 3849 void DecimalFormat::setPadCharacter(const UnicodeString &padChar) {
michael@0 3850 if (padChar.length() > 0) {
michael@0 3851 fPad = padChar.char32At(0);
michael@0 3852 }
michael@0 3853 else {
michael@0 3854 fPad = kDefaultPad;
michael@0 3855 }
michael@0 3856 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3857 handleChanged();
michael@0 3858 #endif
michael@0 3859 }
michael@0 3860
michael@0 3861 /**
michael@0 3862 * Get the position at which padding will take place. This is the location
michael@0 3863 * at which padding will be inserted if the result of <code>format()</code>
michael@0 3864 * is shorter than the format width.
michael@0 3865 * @return the pad position, one of <code>kPadBeforePrefix</code>,
michael@0 3866 * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or
michael@0 3867 * <code>kPadAfterSuffix</code>.
michael@0 3868 * @see #setFormatWidth
michael@0 3869 * @see #getFormatWidth
michael@0 3870 * @see #setPadCharacter
michael@0 3871 * @see #getPadCharacter
michael@0 3872 * @see #setPadPosition
michael@0 3873 * @see #kPadBeforePrefix
michael@0 3874 * @see #kPadAfterPrefix
michael@0 3875 * @see #kPadBeforeSuffix
michael@0 3876 * @see #kPadAfterSuffix
michael@0 3877 */
michael@0 3878 DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const {
michael@0 3879 return fPadPosition;
michael@0 3880 }
michael@0 3881
michael@0 3882 /**
michael@0 3883 * <strong><font face=helvetica color=red>NEW</font></strong>
michael@0 3884 * Set the position at which padding will take place. This is the location
michael@0 3885 * at which padding will be inserted if the result of <code>format()</code>
michael@0 3886 * is shorter than the format width. This has no effect unless padding is
michael@0 3887 * enabled.
michael@0 3888 * @param padPos the pad position, one of <code>kPadBeforePrefix</code>,
michael@0 3889 * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or
michael@0 3890 * <code>kPadAfterSuffix</code>.
michael@0 3891 * @see #setFormatWidth
michael@0 3892 * @see #getFormatWidth
michael@0 3893 * @see #setPadCharacter
michael@0 3894 * @see #getPadCharacter
michael@0 3895 * @see #getPadPosition
michael@0 3896 * @see #kPadBeforePrefix
michael@0 3897 * @see #kPadAfterPrefix
michael@0 3898 * @see #kPadBeforeSuffix
michael@0 3899 * @see #kPadAfterSuffix
michael@0 3900 */
michael@0 3901 void DecimalFormat::setPadPosition(EPadPosition padPos) {
michael@0 3902 fPadPosition = padPos;
michael@0 3903 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3904 handleChanged();
michael@0 3905 #endif
michael@0 3906 }
michael@0 3907
michael@0 3908 /**
michael@0 3909 * Return whether or not scientific notation is used.
michael@0 3910 * @return TRUE if this object formats and parses scientific notation
michael@0 3911 * @see #setScientificNotation
michael@0 3912 * @see #getMinimumExponentDigits
michael@0 3913 * @see #setMinimumExponentDigits
michael@0 3914 * @see #isExponentSignAlwaysShown
michael@0 3915 * @see #setExponentSignAlwaysShown
michael@0 3916 */
michael@0 3917 UBool DecimalFormat::isScientificNotation() const {
michael@0 3918 return fUseExponentialNotation;
michael@0 3919 }
michael@0 3920
michael@0 3921 /**
michael@0 3922 * Set whether or not scientific notation is used.
michael@0 3923 * @param useScientific TRUE if this object formats and parses scientific
michael@0 3924 * notation
michael@0 3925 * @see #isScientificNotation
michael@0 3926 * @see #getMinimumExponentDigits
michael@0 3927 * @see #setMinimumExponentDigits
michael@0 3928 * @see #isExponentSignAlwaysShown
michael@0 3929 * @see #setExponentSignAlwaysShown
michael@0 3930 */
michael@0 3931 void DecimalFormat::setScientificNotation(UBool useScientific) {
michael@0 3932 fUseExponentialNotation = useScientific;
michael@0 3933 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3934 handleChanged();
michael@0 3935 #endif
michael@0 3936 }
michael@0 3937
michael@0 3938 /**
michael@0 3939 * Return the minimum exponent digits that will be shown.
michael@0 3940 * @return the minimum exponent digits that will be shown
michael@0 3941 * @see #setScientificNotation
michael@0 3942 * @see #isScientificNotation
michael@0 3943 * @see #setMinimumExponentDigits
michael@0 3944 * @see #isExponentSignAlwaysShown
michael@0 3945 * @see #setExponentSignAlwaysShown
michael@0 3946 */
michael@0 3947 int8_t DecimalFormat::getMinimumExponentDigits() const {
michael@0 3948 return fMinExponentDigits;
michael@0 3949 }
michael@0 3950
michael@0 3951 /**
michael@0 3952 * Set the minimum exponent digits that will be shown. This has no
michael@0 3953 * effect unless scientific notation is in use.
michael@0 3954 * @param minExpDig a value >= 1 indicating the fewest exponent digits
michael@0 3955 * that will be shown. Values less than 1 will be treated as 1.
michael@0 3956 * @see #setScientificNotation
michael@0 3957 * @see #isScientificNotation
michael@0 3958 * @see #getMinimumExponentDigits
michael@0 3959 * @see #isExponentSignAlwaysShown
michael@0 3960 * @see #setExponentSignAlwaysShown
michael@0 3961 */
michael@0 3962 void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {
michael@0 3963 fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1);
michael@0 3964 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3965 handleChanged();
michael@0 3966 #endif
michael@0 3967 }
michael@0 3968
michael@0 3969 /**
michael@0 3970 * Return whether the exponent sign is always shown.
michael@0 3971 * @return TRUE if the exponent is always prefixed with either the
michael@0 3972 * localized minus sign or the localized plus sign, false if only negative
michael@0 3973 * exponents are prefixed with the localized minus sign.
michael@0 3974 * @see #setScientificNotation
michael@0 3975 * @see #isScientificNotation
michael@0 3976 * @see #setMinimumExponentDigits
michael@0 3977 * @see #getMinimumExponentDigits
michael@0 3978 * @see #setExponentSignAlwaysShown
michael@0 3979 */
michael@0 3980 UBool DecimalFormat::isExponentSignAlwaysShown() const {
michael@0 3981 return fExponentSignAlwaysShown;
michael@0 3982 }
michael@0 3983
michael@0 3984 /**
michael@0 3985 * Set whether the exponent sign is always shown. This has no effect
michael@0 3986 * unless scientific notation is in use.
michael@0 3987 * @param expSignAlways TRUE if the exponent is always prefixed with either
michael@0 3988 * the localized minus sign or the localized plus sign, false if only
michael@0 3989 * negative exponents are prefixed with the localized minus sign.
michael@0 3990 * @see #setScientificNotation
michael@0 3991 * @see #isScientificNotation
michael@0 3992 * @see #setMinimumExponentDigits
michael@0 3993 * @see #getMinimumExponentDigits
michael@0 3994 * @see #isExponentSignAlwaysShown
michael@0 3995 */
michael@0 3996 void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {
michael@0 3997 fExponentSignAlwaysShown = expSignAlways;
michael@0 3998 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 3999 handleChanged();
michael@0 4000 #endif
michael@0 4001 }
michael@0 4002
michael@0 4003 //------------------------------------------------------------------------------
michael@0 4004 // Gets the grouping size of the number pattern. For example, thousand or 10
michael@0 4005 // thousand groupings.
michael@0 4006
michael@0 4007 int32_t
michael@0 4008 DecimalFormat::getGroupingSize() const
michael@0 4009 {
michael@0 4010 return fGroupingSize;
michael@0 4011 }
michael@0 4012
michael@0 4013 //------------------------------------------------------------------------------
michael@0 4014 // Gets the grouping size of the number pattern.
michael@0 4015
michael@0 4016 void
michael@0 4017 DecimalFormat::setGroupingSize(int32_t newValue)
michael@0 4018 {
michael@0 4019 fGroupingSize = newValue;
michael@0 4020 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 4021 handleChanged();
michael@0 4022 #endif
michael@0 4023 }
michael@0 4024
michael@0 4025 //------------------------------------------------------------------------------
michael@0 4026
michael@0 4027 int32_t
michael@0 4028 DecimalFormat::getSecondaryGroupingSize() const
michael@0 4029 {
michael@0 4030 return fGroupingSize2;
michael@0 4031 }
michael@0 4032
michael@0 4033 //------------------------------------------------------------------------------
michael@0 4034
michael@0 4035 void
michael@0 4036 DecimalFormat::setSecondaryGroupingSize(int32_t newValue)
michael@0 4037 {
michael@0 4038 fGroupingSize2 = newValue;
michael@0 4039 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 4040 handleChanged();
michael@0 4041 #endif
michael@0 4042 }
michael@0 4043
michael@0 4044 //------------------------------------------------------------------------------
michael@0 4045 // Checks if to show the decimal separator.
michael@0 4046
michael@0 4047 UBool
michael@0 4048 DecimalFormat::isDecimalSeparatorAlwaysShown() const
michael@0 4049 {
michael@0 4050 return fDecimalSeparatorAlwaysShown;
michael@0 4051 }
michael@0 4052
michael@0 4053 //------------------------------------------------------------------------------
michael@0 4054 // Sets to always show the decimal separator.
michael@0 4055
michael@0 4056 void
michael@0 4057 DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue)
michael@0 4058 {
michael@0 4059 fDecimalSeparatorAlwaysShown = newValue;
michael@0 4060 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 4061 handleChanged();
michael@0 4062 #endif
michael@0 4063 }
michael@0 4064
michael@0 4065 //------------------------------------------------------------------------------
michael@0 4066 // Emits the pattern of this DecimalFormat instance.
michael@0 4067
michael@0 4068 UnicodeString&
michael@0 4069 DecimalFormat::toPattern(UnicodeString& result) const
michael@0 4070 {
michael@0 4071 return toPattern(result, FALSE);
michael@0 4072 }
michael@0 4073
michael@0 4074 //------------------------------------------------------------------------------
michael@0 4075 // Emits the localized pattern this DecimalFormat instance.
michael@0 4076
michael@0 4077 UnicodeString&
michael@0 4078 DecimalFormat::toLocalizedPattern(UnicodeString& result) const
michael@0 4079 {
michael@0 4080 return toPattern(result, TRUE);
michael@0 4081 }
michael@0 4082
michael@0 4083 //------------------------------------------------------------------------------
michael@0 4084 /**
michael@0 4085 * Expand the affix pattern strings into the expanded affix strings. If any
michael@0 4086 * affix pattern string is null, do not expand it. This method should be
michael@0 4087 * called any time the symbols or the affix patterns change in order to keep
michael@0 4088 * the expanded affix strings up to date.
michael@0 4089 * This method also will be called before formatting if format currency
michael@0 4090 * plural names, since the plural name is not a static one, it is
michael@0 4091 * based on the currency plural count, the affix will be known only
michael@0 4092 * after the currency plural count is know.
michael@0 4093 * In which case, the parameter
michael@0 4094 * 'pluralCount' will be a non-null currency plural count.
michael@0 4095 * In all other cases, the 'pluralCount' is null, which means it is not needed.
michael@0 4096 */
michael@0 4097 void DecimalFormat::expandAffixes(const UnicodeString* pluralCount) {
michael@0 4098 FieldPositionHandler none;
michael@0 4099 if (fPosPrefixPattern != 0) {
michael@0 4100 expandAffix(*fPosPrefixPattern, fPositivePrefix, 0, none, FALSE, pluralCount);
michael@0 4101 }
michael@0 4102 if (fPosSuffixPattern != 0) {
michael@0 4103 expandAffix(*fPosSuffixPattern, fPositiveSuffix, 0, none, FALSE, pluralCount);
michael@0 4104 }
michael@0 4105 if (fNegPrefixPattern != 0) {
michael@0 4106 expandAffix(*fNegPrefixPattern, fNegativePrefix, 0, none, FALSE, pluralCount);
michael@0 4107 }
michael@0 4108 if (fNegSuffixPattern != 0) {
michael@0 4109 expandAffix(*fNegSuffixPattern, fNegativeSuffix, 0, none, FALSE, pluralCount);
michael@0 4110 }
michael@0 4111 #ifdef FMT_DEBUG
michael@0 4112 UnicodeString s;
michael@0 4113 s.append(UnicodeString("["))
michael@0 4114 .append(DEREFSTR(fPosPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fPosSuffixPattern))
michael@0 4115 .append((UnicodeString)";") .append(DEREFSTR(fNegPrefixPattern)).append((UnicodeString)"|").append(DEREFSTR(fNegSuffixPattern))
michael@0 4116 .append((UnicodeString)"]->[")
michael@0 4117 .append(fPositivePrefix).append((UnicodeString)"|").append(fPositiveSuffix)
michael@0 4118 .append((UnicodeString)";") .append(fNegativePrefix).append((UnicodeString)"|").append(fNegativeSuffix)
michael@0 4119 .append((UnicodeString)"]\n");
michael@0 4120 debugout(s);
michael@0 4121 #endif
michael@0 4122 }
michael@0 4123
michael@0 4124 /**
michael@0 4125 * Expand an affix pattern into an affix string. All characters in the
michael@0 4126 * pattern are literal unless prefixed by kQuote. The following characters
michael@0 4127 * after kQuote are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
michael@0 4128 * PATTERN_MINUS, and kCurrencySign. If kCurrencySign is doubled (kQuote +
michael@0 4129 * kCurrencySign + kCurrencySign), it is interpreted as an international
michael@0 4130 * currency sign. If CURRENCY_SIGN is tripled, it is interpreted as
michael@0 4131 * currency plural long names, such as "US Dollars".
michael@0 4132 * Any other character after a kQuote represents itself.
michael@0 4133 * kQuote must be followed by another character; kQuote may not occur by
michael@0 4134 * itself at the end of the pattern.
michael@0 4135 *
michael@0 4136 * This method is used in two distinct ways. First, it is used to expand
michael@0 4137 * the stored affix patterns into actual affixes. For this usage, doFormat
michael@0 4138 * must be false. Second, it is used to expand the stored affix patterns
michael@0 4139 * given a specific number (doFormat == true), for those rare cases in
michael@0 4140 * which a currency format references a ChoiceFormat (e.g., en_IN display
michael@0 4141 * name for INR). The number itself is taken from digitList.
michael@0 4142 *
michael@0 4143 * When used in the first way, this method has a side effect: It sets
michael@0 4144 * currencyChoice to a ChoiceFormat object, if the currency's display name
michael@0 4145 * in this locale is a ChoiceFormat pattern (very rare). It only does this
michael@0 4146 * if currencyChoice is null to start with.
michael@0 4147 *
michael@0 4148 * @param pattern the non-null, fPossibly empty pattern
michael@0 4149 * @param affix string to receive the expanded equivalent of pattern.
michael@0 4150 * Previous contents are deleted.
michael@0 4151 * @param doFormat if false, then the pattern will be expanded, and if a
michael@0 4152 * currency symbol is encountered that expands to a ChoiceFormat, the
michael@0 4153 * currencyChoice member variable will be initialized if it is null. If
michael@0 4154 * doFormat is true, then it is assumed that the currencyChoice has been
michael@0 4155 * created, and it will be used to format the value in digitList.
michael@0 4156 * @param pluralCount the plural count. It is only used for currency
michael@0 4157 * plural format. In which case, it is the plural
michael@0 4158 * count of the currency amount. For example,
michael@0 4159 * in en_US, it is the singular "one", or the plural
michael@0 4160 * "other". For all other cases, it is null, and
michael@0 4161 * is not being used.
michael@0 4162 */
michael@0 4163 void DecimalFormat::expandAffix(const UnicodeString& pattern,
michael@0 4164 UnicodeString& affix,
michael@0 4165 double number,
michael@0 4166 FieldPositionHandler& handler,
michael@0 4167 UBool doFormat,
michael@0 4168 const UnicodeString* pluralCount) const {
michael@0 4169 affix.remove();
michael@0 4170 for (int i=0; i<pattern.length(); ) {
michael@0 4171 UChar32 c = pattern.char32At(i);
michael@0 4172 i += U16_LENGTH(c);
michael@0 4173 if (c == kQuote) {
michael@0 4174 c = pattern.char32At(i);
michael@0 4175 i += U16_LENGTH(c);
michael@0 4176 int beginIdx = affix.length();
michael@0 4177 switch (c) {
michael@0 4178 case kCurrencySign: {
michael@0 4179 // As of ICU 2.2 we use the currency object, and
michael@0 4180 // ignore the currency symbols in the DFS, unless
michael@0 4181 // we have a null currency object. This occurs if
michael@0 4182 // resurrecting a pre-2.2 object or if the user
michael@0 4183 // sets a custom DFS.
michael@0 4184 UBool intl = i<pattern.length() &&
michael@0 4185 pattern.char32At(i) == kCurrencySign;
michael@0 4186 UBool plural = FALSE;
michael@0 4187 if (intl) {
michael@0 4188 ++i;
michael@0 4189 plural = i<pattern.length() &&
michael@0 4190 pattern.char32At(i) == kCurrencySign;
michael@0 4191 if (plural) {
michael@0 4192 intl = FALSE;
michael@0 4193 ++i;
michael@0 4194 }
michael@0 4195 }
michael@0 4196 const UChar* currencyUChars = getCurrency();
michael@0 4197 if (currencyUChars[0] != 0) {
michael@0 4198 UErrorCode ec = U_ZERO_ERROR;
michael@0 4199 if (plural && pluralCount != NULL) {
michael@0 4200 // plural name is only needed when pluralCount != null,
michael@0 4201 // which means when formatting currency plural names.
michael@0 4202 // For other cases, pluralCount == null,
michael@0 4203 // and plural names are not needed.
michael@0 4204 int32_t len;
michael@0 4205 CharString pluralCountChar;
michael@0 4206 pluralCountChar.appendInvariantChars(*pluralCount, ec);
michael@0 4207 UBool isChoiceFormat;
michael@0 4208 const UChar* s = ucurr_getPluralName(currencyUChars,
michael@0 4209 fSymbols != NULL ? fSymbols->getLocale().getName() :
michael@0 4210 Locale::getDefault().getName(), &isChoiceFormat,
michael@0 4211 pluralCountChar.data(), &len, &ec);
michael@0 4212 affix += UnicodeString(s, len);
michael@0 4213 handler.addAttribute(kCurrencyField, beginIdx, affix.length());
michael@0 4214 } else if(intl) {
michael@0 4215 affix.append(currencyUChars, -1);
michael@0 4216 handler.addAttribute(kCurrencyField, beginIdx, affix.length());
michael@0 4217 } else {
michael@0 4218 int32_t len;
michael@0 4219 UBool isChoiceFormat;
michael@0 4220 // If fSymbols is NULL, use default locale
michael@0 4221 const UChar* s = ucurr_getName(currencyUChars,
michael@0 4222 fSymbols != NULL ? fSymbols->getLocale().getName() : Locale::getDefault().getName(),
michael@0 4223 UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec);
michael@0 4224 if (isChoiceFormat) {
michael@0 4225 // Two modes here: If doFormat is false, we set up
michael@0 4226 // currencyChoice. If doFormat is true, we use the
michael@0 4227 // previously created currencyChoice to format the
michael@0 4228 // value in digitList.
michael@0 4229 if (!doFormat) {
michael@0 4230 // If the currency is handled by a ChoiceFormat,
michael@0 4231 // then we're not going to use the expanded
michael@0 4232 // patterns. Instantiate the ChoiceFormat and
michael@0 4233 // return.
michael@0 4234 if (fCurrencyChoice == NULL) {
michael@0 4235 // TODO Replace double-check with proper thread-safe code
michael@0 4236 ChoiceFormat* fmt = new ChoiceFormat(UnicodeString(s), ec);
michael@0 4237 if (U_SUCCESS(ec)) {
michael@0 4238 umtx_lock(NULL);
michael@0 4239 if (fCurrencyChoice == NULL) {
michael@0 4240 // Cast away const
michael@0 4241 ((DecimalFormat*)this)->fCurrencyChoice = fmt;
michael@0 4242 fmt = NULL;
michael@0 4243 }
michael@0 4244 umtx_unlock(NULL);
michael@0 4245 delete fmt;
michael@0 4246 }
michael@0 4247 }
michael@0 4248 // We could almost return null or "" here, since the
michael@0 4249 // expanded affixes are almost not used at all
michael@0 4250 // in this situation. However, one method --
michael@0 4251 // toPattern() -- still does use the expanded
michael@0 4252 // affixes, in order to set up a padding
michael@0 4253 // pattern. We use the CURRENCY_SIGN as a
michael@0 4254 // placeholder.
michael@0 4255 affix.append(kCurrencySign);
michael@0 4256 } else {
michael@0 4257 if (fCurrencyChoice != NULL) {
michael@0 4258 FieldPosition pos(0); // ignored
michael@0 4259 if (number < 0) {
michael@0 4260 number = -number;
michael@0 4261 }
michael@0 4262 fCurrencyChoice->format(number, affix, pos);
michael@0 4263 } else {
michael@0 4264 // We only arrive here if the currency choice
michael@0 4265 // format in the locale data is INVALID.
michael@0 4266 affix.append(currencyUChars, -1);
michael@0 4267 handler.addAttribute(kCurrencyField, beginIdx, affix.length());
michael@0 4268 }
michael@0 4269 }
michael@0 4270 continue;
michael@0 4271 }
michael@0 4272 affix += UnicodeString(s, len);
michael@0 4273 handler.addAttribute(kCurrencyField, beginIdx, affix.length());
michael@0 4274 }
michael@0 4275 } else {
michael@0 4276 if(intl) {
michael@0 4277 affix += getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
michael@0 4278 } else {
michael@0 4279 affix += getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
michael@0 4280 }
michael@0 4281 handler.addAttribute(kCurrencyField, beginIdx, affix.length());
michael@0 4282 }
michael@0 4283 break;
michael@0 4284 }
michael@0 4285 case kPatternPercent:
michael@0 4286 affix += getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
michael@0 4287 handler.addAttribute(kPercentField, beginIdx, affix.length());
michael@0 4288 break;
michael@0 4289 case kPatternPerMill:
michael@0 4290 affix += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
michael@0 4291 handler.addAttribute(kPermillField, beginIdx, affix.length());
michael@0 4292 break;
michael@0 4293 case kPatternPlus:
michael@0 4294 affix += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
michael@0 4295 handler.addAttribute(kSignField, beginIdx, affix.length());
michael@0 4296 break;
michael@0 4297 case kPatternMinus:
michael@0 4298 affix += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
michael@0 4299 handler.addAttribute(kSignField, beginIdx, affix.length());
michael@0 4300 break;
michael@0 4301 default:
michael@0 4302 affix.append(c);
michael@0 4303 break;
michael@0 4304 }
michael@0 4305 }
michael@0 4306 else {
michael@0 4307 affix.append(c);
michael@0 4308 }
michael@0 4309 }
michael@0 4310 }
michael@0 4311
michael@0 4312 /**
michael@0 4313 * Append an affix to the given StringBuffer.
michael@0 4314 * @param buf buffer to append to
michael@0 4315 * @param isNegative
michael@0 4316 * @param isPrefix
michael@0 4317 */
michael@0 4318 int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number,
michael@0 4319 FieldPositionHandler& handler,
michael@0 4320 UBool isNegative, UBool isPrefix) const {
michael@0 4321 // plural format precedes choice format
michael@0 4322 if (fCurrencyChoice != 0 &&
michael@0 4323 fCurrencySignCount != fgCurrencySignCountInPluralFormat) {
michael@0 4324 const UnicodeString* affixPat;
michael@0 4325 if (isPrefix) {
michael@0 4326 affixPat = isNegative ? fNegPrefixPattern : fPosPrefixPattern;
michael@0 4327 } else {
michael@0 4328 affixPat = isNegative ? fNegSuffixPattern : fPosSuffixPattern;
michael@0 4329 }
michael@0 4330 if (affixPat) {
michael@0 4331 UnicodeString affixBuf;
michael@0 4332 expandAffix(*affixPat, affixBuf, number, handler, TRUE, NULL);
michael@0 4333 buf.append(affixBuf);
michael@0 4334 return affixBuf.length();
michael@0 4335 }
michael@0 4336 // else someone called a function that reset the pattern.
michael@0 4337 }
michael@0 4338
michael@0 4339 const UnicodeString* affix;
michael@0 4340 if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) {
michael@0 4341 // TODO: get an accurate count of visible fraction digits.
michael@0 4342 UnicodeString pluralCount;
michael@0 4343 int32_t minFractionDigits = this->getMinimumFractionDigits();
michael@0 4344 if (minFractionDigits > 0) {
michael@0 4345 FixedDecimal ni(number, this->getMinimumFractionDigits());
michael@0 4346 pluralCount = fCurrencyPluralInfo->getPluralRules()->select(ni);
michael@0 4347 } else {
michael@0 4348 pluralCount = fCurrencyPluralInfo->getPluralRules()->select(number);
michael@0 4349 }
michael@0 4350 AffixesForCurrency* oneSet;
michael@0 4351 if (fStyle == UNUM_CURRENCY_PLURAL) {
michael@0 4352 oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralCount);
michael@0 4353 } else {
michael@0 4354 oneSet = (AffixesForCurrency*)fAffixesForCurrency->get(pluralCount);
michael@0 4355 }
michael@0 4356 if (isPrefix) {
michael@0 4357 affix = isNegative ? &oneSet->negPrefixForCurrency :
michael@0 4358 &oneSet->posPrefixForCurrency;
michael@0 4359 } else {
michael@0 4360 affix = isNegative ? &oneSet->negSuffixForCurrency :
michael@0 4361 &oneSet->posSuffixForCurrency;
michael@0 4362 }
michael@0 4363 } else {
michael@0 4364 if (isPrefix) {
michael@0 4365 affix = isNegative ? &fNegativePrefix : &fPositivePrefix;
michael@0 4366 } else {
michael@0 4367 affix = isNegative ? &fNegativeSuffix : &fPositiveSuffix;
michael@0 4368 }
michael@0 4369 }
michael@0 4370
michael@0 4371 int32_t begin = (int) buf.length();
michael@0 4372
michael@0 4373 buf.append(*affix);
michael@0 4374
michael@0 4375 if (handler.isRecording()) {
michael@0 4376 int32_t offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kCurrencySymbol));
michael@0 4377 if (offset > -1) {
michael@0 4378 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kCurrencySymbol);
michael@0 4379 handler.addAttribute(kCurrencyField, begin + offset, begin + offset + aff.length());
michael@0 4380 }
michael@0 4381
michael@0 4382 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol));
michael@0 4383 if (offset > -1) {
michael@0 4384 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
michael@0 4385 handler.addAttribute(kCurrencyField, begin + offset, begin + offset + aff.length());
michael@0 4386 }
michael@0 4387
michael@0 4388 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol));
michael@0 4389 if (offset > -1) {
michael@0 4390 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
michael@0 4391 handler.addAttribute(kSignField, begin + offset, begin + offset + aff.length());
michael@0 4392 }
michael@0 4393
michael@0 4394 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol));
michael@0 4395 if (offset > -1) {
michael@0 4396 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
michael@0 4397 handler.addAttribute(kPercentField, begin + offset, begin + offset + aff.length());
michael@0 4398 }
michael@0 4399
michael@0 4400 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol));
michael@0 4401 if (offset > -1) {
michael@0 4402 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
michael@0 4403 handler.addAttribute(kPermillField, begin + offset, begin + offset + aff.length());
michael@0 4404 }
michael@0 4405 }
michael@0 4406 return affix->length();
michael@0 4407 }
michael@0 4408
michael@0 4409 /**
michael@0 4410 * Appends an affix pattern to the given StringBuffer, quoting special
michael@0 4411 * characters as needed. Uses the internal affix pattern, if that exists,
michael@0 4412 * or the literal affix, if the internal affix pattern is null. The
michael@0 4413 * appended string will generate the same affix pattern (or literal affix)
michael@0 4414 * when passed to toPattern().
michael@0 4415 *
michael@0 4416 * @param appendTo the affix string is appended to this
michael@0 4417 * @param affixPattern a pattern such as fPosPrefixPattern; may be null
michael@0 4418 * @param expAffix a corresponding expanded affix, such as fPositivePrefix.
michael@0 4419 * Ignored unless affixPattern is null. If affixPattern is null, then
michael@0 4420 * expAffix is appended as a literal affix.
michael@0 4421 * @param localized true if the appended pattern should contain localized
michael@0 4422 * pattern characters; otherwise, non-localized pattern chars are appended
michael@0 4423 */
michael@0 4424 void DecimalFormat::appendAffixPattern(UnicodeString& appendTo,
michael@0 4425 const UnicodeString* affixPattern,
michael@0 4426 const UnicodeString& expAffix,
michael@0 4427 UBool localized) const {
michael@0 4428 if (affixPattern == 0) {
michael@0 4429 appendAffixPattern(appendTo, expAffix, localized);
michael@0 4430 } else {
michael@0 4431 int i;
michael@0 4432 for (int pos=0; pos<affixPattern->length(); pos=i) {
michael@0 4433 i = affixPattern->indexOf(kQuote, pos);
michael@0 4434 if (i < 0) {
michael@0 4435 UnicodeString s;
michael@0 4436 affixPattern->extractBetween(pos, affixPattern->length(), s);
michael@0 4437 appendAffixPattern(appendTo, s, localized);
michael@0 4438 break;
michael@0 4439 }
michael@0 4440 if (i > pos) {
michael@0 4441 UnicodeString s;
michael@0 4442 affixPattern->extractBetween(pos, i, s);
michael@0 4443 appendAffixPattern(appendTo, s, localized);
michael@0 4444 }
michael@0 4445 UChar32 c = affixPattern->char32At(++i);
michael@0 4446 ++i;
michael@0 4447 if (c == kQuote) {
michael@0 4448 appendTo.append(c).append(c);
michael@0 4449 // Fall through and append another kQuote below
michael@0 4450 } else if (c == kCurrencySign &&
michael@0 4451 i<affixPattern->length() &&
michael@0 4452 affixPattern->char32At(i) == kCurrencySign) {
michael@0 4453 ++i;
michael@0 4454 appendTo.append(c).append(c);
michael@0 4455 } else if (localized) {
michael@0 4456 switch (c) {
michael@0 4457 case kPatternPercent:
michael@0 4458 appendTo += getConstSymbol(DecimalFormatSymbols::kPercentSymbol);
michael@0 4459 break;
michael@0 4460 case kPatternPerMill:
michael@0 4461 appendTo += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol);
michael@0 4462 break;
michael@0 4463 case kPatternPlus:
michael@0 4464 appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
michael@0 4465 break;
michael@0 4466 case kPatternMinus:
michael@0 4467 appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
michael@0 4468 break;
michael@0 4469 default:
michael@0 4470 appendTo.append(c);
michael@0 4471 }
michael@0 4472 } else {
michael@0 4473 appendTo.append(c);
michael@0 4474 }
michael@0 4475 }
michael@0 4476 }
michael@0 4477 }
michael@0 4478
michael@0 4479 /**
michael@0 4480 * Append an affix to the given StringBuffer, using quotes if
michael@0 4481 * there are special characters. Single quotes themselves must be
michael@0 4482 * escaped in either case.
michael@0 4483 */
michael@0 4484 void
michael@0 4485 DecimalFormat::appendAffixPattern(UnicodeString& appendTo,
michael@0 4486 const UnicodeString& affix,
michael@0 4487 UBool localized) const {
michael@0 4488 UBool needQuote;
michael@0 4489 if(localized) {
michael@0 4490 needQuote = affix.indexOf(getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol)) >= 0
michael@0 4491 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol)) >= 0
michael@0 4492 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)) >= 0
michael@0 4493 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol)) >= 0
michael@0 4494 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol)) >= 0
michael@0 4495 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDigitSymbol)) >= 0
michael@0 4496 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol)) >= 0
michael@0 4497 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol)) >= 0
michael@0 4498 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)) >= 0
michael@0 4499 || affix.indexOf(kCurrencySign) >= 0;
michael@0 4500 }
michael@0 4501 else {
michael@0 4502 needQuote = affix.indexOf(kPatternZeroDigit) >= 0
michael@0 4503 || affix.indexOf(kPatternGroupingSeparator) >= 0
michael@0 4504 || affix.indexOf(kPatternDecimalSeparator) >= 0
michael@0 4505 || affix.indexOf(kPatternPercent) >= 0
michael@0 4506 || affix.indexOf(kPatternPerMill) >= 0
michael@0 4507 || affix.indexOf(kPatternDigit) >= 0
michael@0 4508 || affix.indexOf(kPatternSeparator) >= 0
michael@0 4509 || affix.indexOf(kPatternExponent) >= 0
michael@0 4510 || affix.indexOf(kPatternPlus) >= 0
michael@0 4511 || affix.indexOf(kPatternMinus) >= 0
michael@0 4512 || affix.indexOf(kCurrencySign) >= 0;
michael@0 4513 }
michael@0 4514 if (needQuote)
michael@0 4515 appendTo += (UChar)0x0027 /*'\''*/;
michael@0 4516 if (affix.indexOf((UChar)0x0027 /*'\''*/) < 0)
michael@0 4517 appendTo += affix;
michael@0 4518 else {
michael@0 4519 for (int32_t j = 0; j < affix.length(); ) {
michael@0 4520 UChar32 c = affix.char32At(j);
michael@0 4521 j += U16_LENGTH(c);
michael@0 4522 appendTo += c;
michael@0 4523 if (c == 0x0027 /*'\''*/)
michael@0 4524 appendTo += c;
michael@0 4525 }
michael@0 4526 }
michael@0 4527 if (needQuote)
michael@0 4528 appendTo += (UChar)0x0027 /*'\''*/;
michael@0 4529 }
michael@0 4530
michael@0 4531 //------------------------------------------------------------------------------
michael@0 4532
michael@0 4533 UnicodeString&
michael@0 4534 DecimalFormat::toPattern(UnicodeString& result, UBool localized) const
michael@0 4535 {
michael@0 4536 if (fStyle == UNUM_CURRENCY_PLURAL) {
michael@0 4537 // the prefix or suffix pattern might not be defined yet,
michael@0 4538 // so they can not be synthesized,
michael@0 4539 // instead, get them directly.
michael@0 4540 // but it might not be the actual pattern used in formatting.
michael@0 4541 // the actual pattern used in formatting depends on the
michael@0 4542 // formatted number's plural count.
michael@0 4543 result = fFormatPattern;
michael@0 4544 return result;
michael@0 4545 }
michael@0 4546 result.remove();
michael@0 4547 UChar32 zero, sigDigit = kPatternSignificantDigit;
michael@0 4548 UnicodeString digit, group;
michael@0 4549 int32_t i;
michael@0 4550 int32_t roundingDecimalPos = 0; // Pos of decimal in roundingDigits
michael@0 4551 UnicodeString roundingDigits;
michael@0 4552 int32_t padPos = (fFormatWidth > 0) ? fPadPosition : -1;
michael@0 4553 UnicodeString padSpec;
michael@0 4554 UBool useSigDig = areSignificantDigitsUsed();
michael@0 4555
michael@0 4556 if (localized) {
michael@0 4557 digit.append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol));
michael@0 4558 group.append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
michael@0 4559 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
michael@0 4560 if (useSigDig) {
michael@0 4561 sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
michael@0 4562 }
michael@0 4563 }
michael@0 4564 else {
michael@0 4565 digit.append((UChar)kPatternDigit);
michael@0 4566 group.append((UChar)kPatternGroupingSeparator);
michael@0 4567 zero = (UChar32)kPatternZeroDigit;
michael@0 4568 }
michael@0 4569 if (fFormatWidth > 0) {
michael@0 4570 if (localized) {
michael@0 4571 padSpec.append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol));
michael@0 4572 }
michael@0 4573 else {
michael@0 4574 padSpec.append((UChar)kPatternPadEscape);
michael@0 4575 }
michael@0 4576 padSpec.append(fPad);
michael@0 4577 }
michael@0 4578 if (fRoundingIncrement != NULL) {
michael@0 4579 for(i=0; i<fRoundingIncrement->getCount(); ++i) {
michael@0 4580 roundingDigits.append(zero+(fRoundingIncrement->getDigitValue(i))); // Convert to Unicode digit
michael@0 4581 }
michael@0 4582 roundingDecimalPos = fRoundingIncrement->getDecimalAt();
michael@0 4583 }
michael@0 4584 for (int32_t part=0; part<2; ++part) {
michael@0 4585 if (padPos == kPadBeforePrefix) {
michael@0 4586 result.append(padSpec);
michael@0 4587 }
michael@0 4588 appendAffixPattern(result,
michael@0 4589 (part==0 ? fPosPrefixPattern : fNegPrefixPattern),
michael@0 4590 (part==0 ? fPositivePrefix : fNegativePrefix),
michael@0 4591 localized);
michael@0 4592 if (padPos == kPadAfterPrefix && ! padSpec.isEmpty()) {
michael@0 4593 result.append(padSpec);
michael@0 4594 }
michael@0 4595 int32_t sub0Start = result.length();
michael@0 4596 int32_t g = isGroupingUsed() ? _max(0, fGroupingSize) : 0;
michael@0 4597 if (g > 0 && fGroupingSize2 > 0 && fGroupingSize2 != fGroupingSize) {
michael@0 4598 g += fGroupingSize2;
michael@0 4599 }
michael@0 4600 int32_t maxDig = 0, minDig = 0, maxSigDig = 0;
michael@0 4601 if (useSigDig) {
michael@0 4602 minDig = getMinimumSignificantDigits();
michael@0 4603 maxDig = maxSigDig = getMaximumSignificantDigits();
michael@0 4604 } else {
michael@0 4605 minDig = getMinimumIntegerDigits();
michael@0 4606 maxDig = getMaximumIntegerDigits();
michael@0 4607 }
michael@0 4608 if (fUseExponentialNotation) {
michael@0 4609 if (maxDig > kMaxScientificIntegerDigits) {
michael@0 4610 maxDig = 1;
michael@0 4611 }
michael@0 4612 } else if (useSigDig) {
michael@0 4613 maxDig = _max(maxDig, g+1);
michael@0 4614 } else {
michael@0 4615 maxDig = _max(_max(g, getMinimumIntegerDigits()),
michael@0 4616 roundingDecimalPos) + 1;
michael@0 4617 }
michael@0 4618 for (i = maxDig; i > 0; --i) {
michael@0 4619 if (!fUseExponentialNotation && i<maxDig &&
michael@0 4620 isGroupingPosition(i)) {
michael@0 4621 result.append(group);
michael@0 4622 }
michael@0 4623 if (useSigDig) {
michael@0 4624 // #@,@### (maxSigDig == 5, minSigDig == 2)
michael@0 4625 // 65 4321 (1-based pos, count from the right)
michael@0 4626 // Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDig)
michael@0 4627 // Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig
michael@0 4628 if (maxSigDig >= i && i > (maxSigDig - minDig)) {
michael@0 4629 result.append(sigDigit);
michael@0 4630 } else {
michael@0 4631 result.append(digit);
michael@0 4632 }
michael@0 4633 } else {
michael@0 4634 if (! roundingDigits.isEmpty()) {
michael@0 4635 int32_t pos = roundingDecimalPos - i;
michael@0 4636 if (pos >= 0 && pos < roundingDigits.length()) {
michael@0 4637 result.append((UChar) (roundingDigits.char32At(pos) - kPatternZeroDigit + zero));
michael@0 4638 continue;
michael@0 4639 }
michael@0 4640 }
michael@0 4641 if (i<=minDig) {
michael@0 4642 result.append(zero);
michael@0 4643 } else {
michael@0 4644 result.append(digit);
michael@0 4645 }
michael@0 4646 }
michael@0 4647 }
michael@0 4648 if (!useSigDig) {
michael@0 4649 if (getMaximumFractionDigits() > 0 || fDecimalSeparatorAlwaysShown) {
michael@0 4650 if (localized) {
michael@0 4651 result += getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
michael@0 4652 }
michael@0 4653 else {
michael@0 4654 result.append((UChar)kPatternDecimalSeparator);
michael@0 4655 }
michael@0 4656 }
michael@0 4657 int32_t pos = roundingDecimalPos;
michael@0 4658 for (i = 0; i < getMaximumFractionDigits(); ++i) {
michael@0 4659 if (! roundingDigits.isEmpty() && pos < roundingDigits.length()) {
michael@0 4660 if (pos < 0) {
michael@0 4661 result.append(zero);
michael@0 4662 }
michael@0 4663 else {
michael@0 4664 result.append((UChar)(roundingDigits.char32At(pos) - kPatternZeroDigit + zero));
michael@0 4665 }
michael@0 4666 ++pos;
michael@0 4667 continue;
michael@0 4668 }
michael@0 4669 if (i<getMinimumFractionDigits()) {
michael@0 4670 result.append(zero);
michael@0 4671 }
michael@0 4672 else {
michael@0 4673 result.append(digit);
michael@0 4674 }
michael@0 4675 }
michael@0 4676 }
michael@0 4677 if (fUseExponentialNotation) {
michael@0 4678 if (localized) {
michael@0 4679 result += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
michael@0 4680 }
michael@0 4681 else {
michael@0 4682 result.append((UChar)kPatternExponent);
michael@0 4683 }
michael@0 4684 if (fExponentSignAlwaysShown) {
michael@0 4685 if (localized) {
michael@0 4686 result += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
michael@0 4687 }
michael@0 4688 else {
michael@0 4689 result.append((UChar)kPatternPlus);
michael@0 4690 }
michael@0 4691 }
michael@0 4692 for (i=0; i<fMinExponentDigits; ++i) {
michael@0 4693 result.append(zero);
michael@0 4694 }
michael@0 4695 }
michael@0 4696 if (! padSpec.isEmpty() && !fUseExponentialNotation) {
michael@0 4697 int32_t add = fFormatWidth - result.length() + sub0Start
michael@0 4698 - ((part == 0)
michael@0 4699 ? fPositivePrefix.length() + fPositiveSuffix.length()
michael@0 4700 : fNegativePrefix.length() + fNegativeSuffix.length());
michael@0 4701 while (add > 0) {
michael@0 4702 result.insert(sub0Start, digit);
michael@0 4703 ++maxDig;
michael@0 4704 --add;
michael@0 4705 // Only add a grouping separator if we have at least
michael@0 4706 // 2 additional characters to be added, so we don't
michael@0 4707 // end up with ",###".
michael@0 4708 if (add>1 && isGroupingPosition(maxDig)) {
michael@0 4709 result.insert(sub0Start, group);
michael@0 4710 --add;
michael@0 4711 }
michael@0 4712 }
michael@0 4713 }
michael@0 4714 if (fPadPosition == kPadBeforeSuffix && ! padSpec.isEmpty()) {
michael@0 4715 result.append(padSpec);
michael@0 4716 }
michael@0 4717 if (part == 0) {
michael@0 4718 appendAffixPattern(result, fPosSuffixPattern, fPositiveSuffix, localized);
michael@0 4719 if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) {
michael@0 4720 result.append(padSpec);
michael@0 4721 }
michael@0 4722 UBool isDefault = FALSE;
michael@0 4723 if ((fNegSuffixPattern == fPosSuffixPattern && // both null
michael@0 4724 fNegativeSuffix == fPositiveSuffix)
michael@0 4725 || (fNegSuffixPattern != 0 && fPosSuffixPattern != 0 &&
michael@0 4726 *fNegSuffixPattern == *fPosSuffixPattern))
michael@0 4727 {
michael@0 4728 if (fNegPrefixPattern != NULL && fPosPrefixPattern != NULL)
michael@0 4729 {
michael@0 4730 int32_t length = fPosPrefixPattern->length();
michael@0 4731 isDefault = fNegPrefixPattern->length() == (length+2) &&
michael@0 4732 (*fNegPrefixPattern)[(int32_t)0] == kQuote &&
michael@0 4733 (*fNegPrefixPattern)[(int32_t)1] == kPatternMinus &&
michael@0 4734 fNegPrefixPattern->compare(2, length, *fPosPrefixPattern, 0, length) == 0;
michael@0 4735 }
michael@0 4736 if (!isDefault &&
michael@0 4737 fNegPrefixPattern == NULL && fPosPrefixPattern == NULL)
michael@0 4738 {
michael@0 4739 int32_t length = fPositivePrefix.length();
michael@0 4740 isDefault = fNegativePrefix.length() == (length+1) &&
michael@0 4741 fNegativePrefix.compare(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol)) == 0 &&
michael@0 4742 fNegativePrefix.compare(1, length, fPositivePrefix, 0, length) == 0;
michael@0 4743 }
michael@0 4744 }
michael@0 4745 if (isDefault) {
michael@0 4746 break; // Don't output default negative subpattern
michael@0 4747 } else {
michael@0 4748 if (localized) {
michael@0 4749 result += getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol);
michael@0 4750 }
michael@0 4751 else {
michael@0 4752 result.append((UChar)kPatternSeparator);
michael@0 4753 }
michael@0 4754 }
michael@0 4755 } else {
michael@0 4756 appendAffixPattern(result, fNegSuffixPattern, fNegativeSuffix, localized);
michael@0 4757 if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) {
michael@0 4758 result.append(padSpec);
michael@0 4759 }
michael@0 4760 }
michael@0 4761 }
michael@0 4762
michael@0 4763 return result;
michael@0 4764 }
michael@0 4765
michael@0 4766 //------------------------------------------------------------------------------
michael@0 4767
michael@0 4768 void
michael@0 4769 DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status)
michael@0 4770 {
michael@0 4771 UParseError parseError;
michael@0 4772 applyPattern(pattern, FALSE, parseError, status);
michael@0 4773 }
michael@0 4774
michael@0 4775 //------------------------------------------------------------------------------
michael@0 4776
michael@0 4777 void
michael@0 4778 DecimalFormat::applyPattern(const UnicodeString& pattern,
michael@0 4779 UParseError& parseError,
michael@0 4780 UErrorCode& status)
michael@0 4781 {
michael@0 4782 applyPattern(pattern, FALSE, parseError, status);
michael@0 4783 }
michael@0 4784 //------------------------------------------------------------------------------
michael@0 4785
michael@0 4786 void
michael@0 4787 DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status)
michael@0 4788 {
michael@0 4789 UParseError parseError;
michael@0 4790 applyPattern(pattern, TRUE,parseError,status);
michael@0 4791 }
michael@0 4792
michael@0 4793 //------------------------------------------------------------------------------
michael@0 4794
michael@0 4795 void
michael@0 4796 DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern,
michael@0 4797 UParseError& parseError,
michael@0 4798 UErrorCode& status)
michael@0 4799 {
michael@0 4800 applyPattern(pattern, TRUE,parseError,status);
michael@0 4801 }
michael@0 4802
michael@0 4803 //------------------------------------------------------------------------------
michael@0 4804
michael@0 4805 void
michael@0 4806 DecimalFormat::applyPatternWithoutExpandAffix(const UnicodeString& pattern,
michael@0 4807 UBool localized,
michael@0 4808 UParseError& parseError,
michael@0 4809 UErrorCode& status)
michael@0 4810 {
michael@0 4811 if (U_FAILURE(status))
michael@0 4812 {
michael@0 4813 return;
michael@0 4814 }
michael@0 4815 // Clear error struct
michael@0 4816 parseError.offset = -1;
michael@0 4817 parseError.preContext[0] = parseError.postContext[0] = (UChar)0;
michael@0 4818
michael@0 4819 // Set the significant pattern symbols
michael@0 4820 UChar32 zeroDigit = kPatternZeroDigit; // '0'
michael@0 4821 UChar32 sigDigit = kPatternSignificantDigit; // '@'
michael@0 4822 UnicodeString groupingSeparator ((UChar)kPatternGroupingSeparator);
michael@0 4823 UnicodeString decimalSeparator ((UChar)kPatternDecimalSeparator);
michael@0 4824 UnicodeString percent ((UChar)kPatternPercent);
michael@0 4825 UnicodeString perMill ((UChar)kPatternPerMill);
michael@0 4826 UnicodeString digit ((UChar)kPatternDigit); // '#'
michael@0 4827 UnicodeString separator ((UChar)kPatternSeparator);
michael@0 4828 UnicodeString exponent ((UChar)kPatternExponent);
michael@0 4829 UnicodeString plus ((UChar)kPatternPlus);
michael@0 4830 UnicodeString minus ((UChar)kPatternMinus);
michael@0 4831 UnicodeString padEscape ((UChar)kPatternPadEscape);
michael@0 4832 // Substitute with the localized symbols if necessary
michael@0 4833 if (localized) {
michael@0 4834 zeroDigit = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
michael@0 4835 sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol).char32At(0);
michael@0 4836 groupingSeparator. remove().append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol));
michael@0 4837 decimalSeparator. remove().append(getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol));
michael@0 4838 percent. remove().append(getConstSymbol(DecimalFormatSymbols::kPercentSymbol));
michael@0 4839 perMill. remove().append(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol));
michael@0 4840 digit. remove().append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol));
michael@0 4841 separator. remove().append(getConstSymbol(DecimalFormatSymbols::kPatternSeparatorSymbol));
michael@0 4842 exponent. remove().append(getConstSymbol(DecimalFormatSymbols::kExponentialSymbol));
michael@0 4843 plus. remove().append(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol));
michael@0 4844 minus. remove().append(getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol));
michael@0 4845 padEscape. remove().append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol));
michael@0 4846 }
michael@0 4847 UChar nineDigit = (UChar)(zeroDigit + 9);
michael@0 4848 int32_t digitLen = digit.length();
michael@0 4849 int32_t groupSepLen = groupingSeparator.length();
michael@0 4850 int32_t decimalSepLen = decimalSeparator.length();
michael@0 4851
michael@0 4852 int32_t pos = 0;
michael@0 4853 int32_t patLen = pattern.length();
michael@0 4854 // Part 0 is the positive pattern. Part 1, if present, is the negative
michael@0 4855 // pattern.
michael@0 4856 for (int32_t part=0; part<2 && pos<patLen; ++part) {
michael@0 4857 // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix,
michael@0 4858 // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is
michael@0 4859 // between the prefix and suffix, and consists of pattern
michael@0 4860 // characters. In the prefix and suffix, percent, perMill, and
michael@0 4861 // currency symbols are recognized and translated.
michael@0 4862 int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0;
michael@0 4863
michael@0 4864 // It's important that we don't change any fields of this object
michael@0 4865 // prematurely. We set the following variables for the multiplier,
michael@0 4866 // grouping, etc., and then only change the actual object fields if
michael@0 4867 // everything parses correctly. This also lets us register
michael@0 4868 // the data from part 0 and ignore the part 1, except for the
michael@0 4869 // prefix and suffix.
michael@0 4870 UnicodeString prefix;
michael@0 4871 UnicodeString suffix;
michael@0 4872 int32_t decimalPos = -1;
michael@0 4873 int32_t multiplier = 1;
michael@0 4874 int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sigDigitCount = 0;
michael@0 4875 int8_t groupingCount = -1;
michael@0 4876 int8_t groupingCount2 = -1;
michael@0 4877 int32_t padPos = -1;
michael@0 4878 UChar32 padChar = 0;
michael@0 4879 int32_t roundingPos = -1;
michael@0 4880 DigitList roundingInc;
michael@0 4881 int8_t expDigits = -1;
michael@0 4882 UBool expSignAlways = FALSE;
michael@0 4883
michael@0 4884 // The affix is either the prefix or the suffix.
michael@0 4885 UnicodeString* affix = &prefix;
michael@0 4886
michael@0 4887 int32_t start = pos;
michael@0 4888 UBool isPartDone = FALSE;
michael@0 4889 UChar32 ch;
michael@0 4890
michael@0 4891 for (; !isPartDone && pos < patLen; ) {
michael@0 4892 // Todo: account for surrogate pairs
michael@0 4893 ch = pattern.char32At(pos);
michael@0 4894 switch (subpart) {
michael@0 4895 case 0: // Pattern proper subpart (between prefix & suffix)
michael@0 4896 // Process the digits, decimal, and grouping characters. We
michael@0 4897 // record five pieces of information. We expect the digits
michael@0 4898 // to occur in the pattern ####00.00####, and we record the
michael@0 4899 // number of left digits, zero (central) digits, and right
michael@0 4900 // digits. The position of the last grouping character is
michael@0 4901 // recorded (should be somewhere within the first two blocks
michael@0 4902 // of characters), as is the position of the decimal point,
michael@0 4903 // if any (should be in the zero digits). If there is no
michael@0 4904 // decimal point, then there should be no right digits.
michael@0 4905 if (pattern.compare(pos, digitLen, digit) == 0) {
michael@0 4906 if (zeroDigitCount > 0 || sigDigitCount > 0) {
michael@0 4907 ++digitRightCount;
michael@0 4908 } else {
michael@0 4909 ++digitLeftCount;
michael@0 4910 }
michael@0 4911 if (groupingCount >= 0 && decimalPos < 0) {
michael@0 4912 ++groupingCount;
michael@0 4913 }
michael@0 4914 pos += digitLen;
michael@0 4915 } else if ((ch >= zeroDigit && ch <= nineDigit) ||
michael@0 4916 ch == sigDigit) {
michael@0 4917 if (digitRightCount > 0) {
michael@0 4918 // Unexpected '0'
michael@0 4919 debug("Unexpected '0'")
michael@0 4920 status = U_UNEXPECTED_TOKEN;
michael@0 4921 syntaxError(pattern,pos,parseError);
michael@0 4922 return;
michael@0 4923 }
michael@0 4924 if (ch == sigDigit) {
michael@0 4925 ++sigDigitCount;
michael@0 4926 } else {
michael@0 4927 if (ch != zeroDigit && roundingPos < 0) {
michael@0 4928 roundingPos = digitLeftCount + zeroDigitCount;
michael@0 4929 }
michael@0 4930 if (roundingPos >= 0) {
michael@0 4931 roundingInc.append((char)(ch - zeroDigit + '0'));
michael@0 4932 }
michael@0 4933 ++zeroDigitCount;
michael@0 4934 }
michael@0 4935 if (groupingCount >= 0 && decimalPos < 0) {
michael@0 4936 ++groupingCount;
michael@0 4937 }
michael@0 4938 pos += U16_LENGTH(ch);
michael@0 4939 } else if (pattern.compare(pos, groupSepLen, groupingSeparator) == 0) {
michael@0 4940 if (decimalPos >= 0) {
michael@0 4941 // Grouping separator after decimal
michael@0 4942 debug("Grouping separator after decimal")
michael@0 4943 status = U_UNEXPECTED_TOKEN;
michael@0 4944 syntaxError(pattern,pos,parseError);
michael@0 4945 return;
michael@0 4946 }
michael@0 4947 groupingCount2 = groupingCount;
michael@0 4948 groupingCount = 0;
michael@0 4949 pos += groupSepLen;
michael@0 4950 } else if (pattern.compare(pos, decimalSepLen, decimalSeparator) == 0) {
michael@0 4951 if (decimalPos >= 0) {
michael@0 4952 // Multiple decimal separators
michael@0 4953 debug("Multiple decimal separators")
michael@0 4954 status = U_MULTIPLE_DECIMAL_SEPARATORS;
michael@0 4955 syntaxError(pattern,pos,parseError);
michael@0 4956 return;
michael@0 4957 }
michael@0 4958 // Intentionally incorporate the digitRightCount,
michael@0 4959 // even though it is illegal for this to be > 0
michael@0 4960 // at this point. We check pattern syntax below.
michael@0 4961 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
michael@0 4962 pos += decimalSepLen;
michael@0 4963 } else {
michael@0 4964 if (pattern.compare(pos, exponent.length(), exponent) == 0) {
michael@0 4965 if (expDigits >= 0) {
michael@0 4966 // Multiple exponential symbols
michael@0 4967 debug("Multiple exponential symbols")
michael@0 4968 status = U_MULTIPLE_EXPONENTIAL_SYMBOLS;
michael@0 4969 syntaxError(pattern,pos,parseError);
michael@0 4970 return;
michael@0 4971 }
michael@0 4972 if (groupingCount >= 0) {
michael@0 4973 // Grouping separator in exponential pattern
michael@0 4974 debug("Grouping separator in exponential pattern")
michael@0 4975 status = U_MALFORMED_EXPONENTIAL_PATTERN;
michael@0 4976 syntaxError(pattern,pos,parseError);
michael@0 4977 return;
michael@0 4978 }
michael@0 4979 pos += exponent.length();
michael@0 4980 // Check for positive prefix
michael@0 4981 if (pos < patLen
michael@0 4982 && pattern.compare(pos, plus.length(), plus) == 0) {
michael@0 4983 expSignAlways = TRUE;
michael@0 4984 pos += plus.length();
michael@0 4985 }
michael@0 4986 // Use lookahead to parse out the exponential part of the
michael@0 4987 // pattern, then jump into suffix subpart.
michael@0 4988 expDigits = 0;
michael@0 4989 while (pos < patLen &&
michael@0 4990 pattern.char32At(pos) == zeroDigit) {
michael@0 4991 ++expDigits;
michael@0 4992 pos += U16_LENGTH(zeroDigit);
michael@0 4993 }
michael@0 4994
michael@0 4995 // 1. Require at least one mantissa pattern digit
michael@0 4996 // 2. Disallow "#+ @" in mantissa
michael@0 4997 // 3. Require at least one exponent pattern digit
michael@0 4998 if (((digitLeftCount + zeroDigitCount) < 1 &&
michael@0 4999 (sigDigitCount + digitRightCount) < 1) ||
michael@0 5000 (sigDigitCount > 0 && digitLeftCount > 0) ||
michael@0 5001 expDigits < 1) {
michael@0 5002 // Malformed exponential pattern
michael@0 5003 debug("Malformed exponential pattern")
michael@0 5004 status = U_MALFORMED_EXPONENTIAL_PATTERN;
michael@0 5005 syntaxError(pattern,pos,parseError);
michael@0 5006 return;
michael@0 5007 }
michael@0 5008 }
michael@0 5009 // Transition to suffix subpart
michael@0 5010 subpart = 2; // suffix subpart
michael@0 5011 affix = &suffix;
michael@0 5012 sub0Limit = pos;
michael@0 5013 continue;
michael@0 5014 }
michael@0 5015 break;
michael@0 5016 case 1: // Prefix subpart
michael@0 5017 case 2: // Suffix subpart
michael@0 5018 // Process the prefix / suffix characters
michael@0 5019 // Process unquoted characters seen in prefix or suffix
michael@0 5020 // subpart.
michael@0 5021
michael@0 5022 // Several syntax characters implicitly begins the
michael@0 5023 // next subpart if we are in the prefix; otherwise
michael@0 5024 // they are illegal if unquoted.
michael@0 5025 if (!pattern.compare(pos, digitLen, digit) ||
michael@0 5026 !pattern.compare(pos, groupSepLen, groupingSeparator) ||
michael@0 5027 !pattern.compare(pos, decimalSepLen, decimalSeparator) ||
michael@0 5028 (ch >= zeroDigit && ch <= nineDigit) ||
michael@0 5029 ch == sigDigit) {
michael@0 5030 if (subpart == 1) { // prefix subpart
michael@0 5031 subpart = 0; // pattern proper subpart
michael@0 5032 sub0Start = pos; // Reprocess this character
michael@0 5033 continue;
michael@0 5034 } else {
michael@0 5035 status = U_UNQUOTED_SPECIAL;
michael@0 5036 syntaxError(pattern,pos,parseError);
michael@0 5037 return;
michael@0 5038 }
michael@0 5039 } else if (ch == kCurrencySign) {
michael@0 5040 affix->append(kQuote); // Encode currency
michael@0 5041 // Use lookahead to determine if the currency sign is
michael@0 5042 // doubled or not.
michael@0 5043 U_ASSERT(U16_LENGTH(kCurrencySign) == 1);
michael@0 5044 if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrencySign) {
michael@0 5045 affix->append(kCurrencySign);
michael@0 5046 ++pos; // Skip over the doubled character
michael@0 5047 if ((pos+1) < pattern.length() &&
michael@0 5048 pattern[pos+1] == kCurrencySign) {
michael@0 5049 affix->append(kCurrencySign);
michael@0 5050 ++pos; // Skip over the doubled character
michael@0 5051 fCurrencySignCount = fgCurrencySignCountInPluralFormat;
michael@0 5052 } else {
michael@0 5053 fCurrencySignCount = fgCurrencySignCountInISOFormat;
michael@0 5054 }
michael@0 5055 } else {
michael@0 5056 fCurrencySignCount = fgCurrencySignCountInSymbolFormat;
michael@0 5057 }
michael@0 5058 // Fall through to append(ch)
michael@0 5059 } else if (ch == kQuote) {
michael@0 5060 // A quote outside quotes indicates either the opening
michael@0 5061 // quote or two quotes, which is a quote literal. That is,
michael@0 5062 // we have the first quote in 'do' or o''clock.
michael@0 5063 U_ASSERT(U16_LENGTH(kQuote) == 1);
michael@0 5064 ++pos;
michael@0 5065 if (pos < pattern.length() && pattern[pos] == kQuote) {
michael@0 5066 affix->append(kQuote); // Encode quote
michael@0 5067 // Fall through to append(ch)
michael@0 5068 } else {
michael@0 5069 subpart += 2; // open quote
michael@0 5070 continue;
michael@0 5071 }
michael@0 5072 } else if (pattern.compare(pos, separator.length(), separator) == 0) {
michael@0 5073 // Don't allow separators in the prefix, and don't allow
michael@0 5074 // separators in the second pattern (part == 1).
michael@0 5075 if (subpart == 1 || part == 1) {
michael@0 5076 // Unexpected separator
michael@0 5077 debug("Unexpected separator")
michael@0 5078 status = U_UNEXPECTED_TOKEN;
michael@0 5079 syntaxError(pattern,pos,parseError);
michael@0 5080 return;
michael@0 5081 }
michael@0 5082 sub2Limit = pos;
michael@0 5083 isPartDone = TRUE; // Go to next part
michael@0 5084 pos += separator.length();
michael@0 5085 break;
michael@0 5086 } else if (pattern.compare(pos, percent.length(), percent) == 0) {
michael@0 5087 // Next handle characters which are appended directly.
michael@0 5088 if (multiplier != 1) {
michael@0 5089 // Too many percent/perMill characters
michael@0 5090 debug("Too many percent characters")
michael@0 5091 status = U_MULTIPLE_PERCENT_SYMBOLS;
michael@0 5092 syntaxError(pattern,pos,parseError);
michael@0 5093 return;
michael@0 5094 }
michael@0 5095 affix->append(kQuote); // Encode percent/perMill
michael@0 5096 affix->append(kPatternPercent); // Use unlocalized pattern char
michael@0 5097 multiplier = 100;
michael@0 5098 pos += percent.length();
michael@0 5099 break;
michael@0 5100 } else if (pattern.compare(pos, perMill.length(), perMill) == 0) {
michael@0 5101 // Next handle characters which are appended directly.
michael@0 5102 if (multiplier != 1) {
michael@0 5103 // Too many percent/perMill characters
michael@0 5104 debug("Too many perMill characters")
michael@0 5105 status = U_MULTIPLE_PERMILL_SYMBOLS;
michael@0 5106 syntaxError(pattern,pos,parseError);
michael@0 5107 return;
michael@0 5108 }
michael@0 5109 affix->append(kQuote); // Encode percent/perMill
michael@0 5110 affix->append(kPatternPerMill); // Use unlocalized pattern char
michael@0 5111 multiplier = 1000;
michael@0 5112 pos += perMill.length();
michael@0 5113 break;
michael@0 5114 } else if (pattern.compare(pos, padEscape.length(), padEscape) == 0) {
michael@0 5115 if (padPos >= 0 || // Multiple pad specifiers
michael@0 5116 (pos+1) == pattern.length()) { // Nothing after padEscape
michael@0 5117 debug("Multiple pad specifiers")
michael@0 5118 status = U_MULTIPLE_PAD_SPECIFIERS;
michael@0 5119 syntaxError(pattern,pos,parseError);
michael@0 5120 return;
michael@0 5121 }
michael@0 5122 padPos = pos;
michael@0 5123 pos += padEscape.length();
michael@0 5124 padChar = pattern.char32At(pos);
michael@0 5125 pos += U16_LENGTH(padChar);
michael@0 5126 break;
michael@0 5127 } else if (pattern.compare(pos, minus.length(), minus) == 0) {
michael@0 5128 affix->append(kQuote); // Encode minus
michael@0 5129 affix->append(kPatternMinus);
michael@0 5130 pos += minus.length();
michael@0 5131 break;
michael@0 5132 } else if (pattern.compare(pos, plus.length(), plus) == 0) {
michael@0 5133 affix->append(kQuote); // Encode plus
michael@0 5134 affix->append(kPatternPlus);
michael@0 5135 pos += plus.length();
michael@0 5136 break;
michael@0 5137 }
michael@0 5138 // Unquoted, non-special characters fall through to here, as
michael@0 5139 // well as other code which needs to append something to the
michael@0 5140 // affix.
michael@0 5141 affix->append(ch);
michael@0 5142 pos += U16_LENGTH(ch);
michael@0 5143 break;
michael@0 5144 case 3: // Prefix subpart, in quote
michael@0 5145 case 4: // Suffix subpart, in quote
michael@0 5146 // A quote within quotes indicates either the closing
michael@0 5147 // quote or two quotes, which is a quote literal. That is,
michael@0 5148 // we have the second quote in 'do' or 'don''t'.
michael@0 5149 if (ch == kQuote) {
michael@0 5150 ++pos;
michael@0 5151 if (pos < pattern.length() && pattern[pos] == kQuote) {
michael@0 5152 affix->append(kQuote); // Encode quote
michael@0 5153 // Fall through to append(ch)
michael@0 5154 } else {
michael@0 5155 subpart -= 2; // close quote
michael@0 5156 continue;
michael@0 5157 }
michael@0 5158 }
michael@0 5159 affix->append(ch);
michael@0 5160 pos += U16_LENGTH(ch);
michael@0 5161 break;
michael@0 5162 }
michael@0 5163 }
michael@0 5164
michael@0 5165 if (sub0Limit == 0) {
michael@0 5166 sub0Limit = pattern.length();
michael@0 5167 }
michael@0 5168
michael@0 5169 if (sub2Limit == 0) {
michael@0 5170 sub2Limit = pattern.length();
michael@0 5171 }
michael@0 5172
michael@0 5173 /* Handle patterns with no '0' pattern character. These patterns
michael@0 5174 * are legal, but must be recodified to make sense. "##.###" ->
michael@0 5175 * "#0.###". ".###" -> ".0##".
michael@0 5176 *
michael@0 5177 * We allow patterns of the form "####" to produce a zeroDigitCount
michael@0 5178 * of zero (got that?); although this seems like it might make it
michael@0 5179 * possible for format() to produce empty strings, format() checks
michael@0 5180 * for this condition and outputs a zero digit in this situation.
michael@0 5181 * Having a zeroDigitCount of zero yields a minimum integer digits
michael@0 5182 * of zero, which allows proper round-trip patterns. We don't want
michael@0 5183 * "#" to become "#0" when toPattern() is called (even though that's
michael@0 5184 * what it really is, semantically).
michael@0 5185 */
michael@0 5186 if (zeroDigitCount == 0 && sigDigitCount == 0 &&
michael@0 5187 digitLeftCount > 0 && decimalPos >= 0) {
michael@0 5188 // Handle "###.###" and "###." and ".###"
michael@0 5189 int n = decimalPos;
michael@0 5190 if (n == 0)
michael@0 5191 ++n; // Handle ".###"
michael@0 5192 digitRightCount = digitLeftCount - n;
michael@0 5193 digitLeftCount = n - 1;
michael@0 5194 zeroDigitCount = 1;
michael@0 5195 }
michael@0 5196
michael@0 5197 // Do syntax checking on the digits, decimal points, and quotes.
michael@0 5198 if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) ||
michael@0 5199 (decimalPos >= 0 &&
michael@0 5200 (sigDigitCount > 0 ||
michael@0 5201 decimalPos < digitLeftCount ||
michael@0 5202 decimalPos > (digitLeftCount + zeroDigitCount))) ||
michael@0 5203 groupingCount == 0 || groupingCount2 == 0 ||
michael@0 5204 (sigDigitCount > 0 && zeroDigitCount > 0) ||
michael@0 5205 subpart > 2)
michael@0 5206 { // subpart > 2 == unmatched quote
michael@0 5207 debug("Syntax error")
michael@0 5208 status = U_PATTERN_SYNTAX_ERROR;
michael@0 5209 syntaxError(pattern,pos,parseError);
michael@0 5210 return;
michael@0 5211 }
michael@0 5212
michael@0 5213 // Make sure pad is at legal position before or after affix.
michael@0 5214 if (padPos >= 0) {
michael@0 5215 if (padPos == start) {
michael@0 5216 padPos = kPadBeforePrefix;
michael@0 5217 } else if (padPos+2 == sub0Start) {
michael@0 5218 padPos = kPadAfterPrefix;
michael@0 5219 } else if (padPos == sub0Limit) {
michael@0 5220 padPos = kPadBeforeSuffix;
michael@0 5221 } else if (padPos+2 == sub2Limit) {
michael@0 5222 padPos = kPadAfterSuffix;
michael@0 5223 } else {
michael@0 5224 // Illegal pad position
michael@0 5225 debug("Illegal pad position")
michael@0 5226 status = U_ILLEGAL_PAD_POSITION;
michael@0 5227 syntaxError(pattern,pos,parseError);
michael@0 5228 return;
michael@0 5229 }
michael@0 5230 }
michael@0 5231
michael@0 5232 if (part == 0) {
michael@0 5233 delete fPosPrefixPattern;
michael@0 5234 delete fPosSuffixPattern;
michael@0 5235 delete fNegPrefixPattern;
michael@0 5236 delete fNegSuffixPattern;
michael@0 5237 fPosPrefixPattern = new UnicodeString(prefix);
michael@0 5238 /* test for NULL */
michael@0 5239 if (fPosPrefixPattern == 0) {
michael@0 5240 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5241 return;
michael@0 5242 }
michael@0 5243 fPosSuffixPattern = new UnicodeString(suffix);
michael@0 5244 /* test for NULL */
michael@0 5245 if (fPosSuffixPattern == 0) {
michael@0 5246 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5247 delete fPosPrefixPattern;
michael@0 5248 return;
michael@0 5249 }
michael@0 5250 fNegPrefixPattern = 0;
michael@0 5251 fNegSuffixPattern = 0;
michael@0 5252
michael@0 5253 fUseExponentialNotation = (expDigits >= 0);
michael@0 5254 if (fUseExponentialNotation) {
michael@0 5255 fMinExponentDigits = expDigits;
michael@0 5256 }
michael@0 5257 fExponentSignAlwaysShown = expSignAlways;
michael@0 5258 int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
michael@0 5259 // The effectiveDecimalPos is the position the decimal is at or
michael@0 5260 // would be at if there is no decimal. Note that if
michael@0 5261 // decimalPos<0, then digitTotalCount == digitLeftCount +
michael@0 5262 // zeroDigitCount.
michael@0 5263 int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount;
michael@0 5264 UBool isSigDig = (sigDigitCount > 0);
michael@0 5265 setSignificantDigitsUsed(isSigDig);
michael@0 5266 if (isSigDig) {
michael@0 5267 setMinimumSignificantDigits(sigDigitCount);
michael@0 5268 setMaximumSignificantDigits(sigDigitCount + digitRightCount);
michael@0 5269 } else {
michael@0 5270 int32_t minInt = effectiveDecimalPos - digitLeftCount;
michael@0 5271 setMinimumIntegerDigits(minInt);
michael@0 5272 setMaximumIntegerDigits(fUseExponentialNotation
michael@0 5273 ? digitLeftCount + getMinimumIntegerDigits()
michael@0 5274 : NumberFormat::gDefaultMaxIntegerDigits);
michael@0 5275 setMaximumFractionDigits(decimalPos >= 0
michael@0 5276 ? (digitTotalCount - decimalPos) : 0);
michael@0 5277 setMinimumFractionDigits(decimalPos >= 0
michael@0 5278 ? (digitLeftCount + zeroDigitCount - decimalPos) : 0);
michael@0 5279 }
michael@0 5280 setGroupingUsed(groupingCount > 0);
michael@0 5281 fGroupingSize = (groupingCount > 0) ? groupingCount : 0;
michael@0 5282 fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCount)
michael@0 5283 ? groupingCount2 : 0;
michael@0 5284 setMultiplier(multiplier);
michael@0 5285 setDecimalSeparatorAlwaysShown(decimalPos == 0
michael@0 5286 || decimalPos == digitTotalCount);
michael@0 5287 if (padPos >= 0) {
michael@0 5288 fPadPosition = (EPadPosition) padPos;
michael@0 5289 // To compute the format width, first set up sub0Limit -
michael@0 5290 // sub0Start. Add in prefix/suffix length later.
michael@0 5291
michael@0 5292 // fFormatWidth = prefix.length() + suffix.length() +
michael@0 5293 // sub0Limit - sub0Start;
michael@0 5294 fFormatWidth = sub0Limit - sub0Start;
michael@0 5295 fPad = padChar;
michael@0 5296 } else {
michael@0 5297 fFormatWidth = 0;
michael@0 5298 }
michael@0 5299 if (roundingPos >= 0) {
michael@0 5300 roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos);
michael@0 5301 if (fRoundingIncrement != NULL) {
michael@0 5302 *fRoundingIncrement = roundingInc;
michael@0 5303 } else {
michael@0 5304 fRoundingIncrement = new DigitList(roundingInc);
michael@0 5305 /* test for NULL */
michael@0 5306 if (fRoundingIncrement == NULL) {
michael@0 5307 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5308 delete fPosPrefixPattern;
michael@0 5309 delete fPosSuffixPattern;
michael@0 5310 return;
michael@0 5311 }
michael@0 5312 }
michael@0 5313 fRoundingMode = kRoundHalfEven;
michael@0 5314 } else {
michael@0 5315 setRoundingIncrement(0.0);
michael@0 5316 }
michael@0 5317 } else {
michael@0 5318 fNegPrefixPattern = new UnicodeString(prefix);
michael@0 5319 /* test for NULL */
michael@0 5320 if (fNegPrefixPattern == 0) {
michael@0 5321 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5322 return;
michael@0 5323 }
michael@0 5324 fNegSuffixPattern = new UnicodeString(suffix);
michael@0 5325 /* test for NULL */
michael@0 5326 if (fNegSuffixPattern == 0) {
michael@0 5327 delete fNegPrefixPattern;
michael@0 5328 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5329 return;
michael@0 5330 }
michael@0 5331 }
michael@0 5332 }
michael@0 5333
michael@0 5334 if (pattern.length() == 0) {
michael@0 5335 delete fNegPrefixPattern;
michael@0 5336 delete fNegSuffixPattern;
michael@0 5337 fNegPrefixPattern = NULL;
michael@0 5338 fNegSuffixPattern = NULL;
michael@0 5339 if (fPosPrefixPattern != NULL) {
michael@0 5340 fPosPrefixPattern->remove();
michael@0 5341 } else {
michael@0 5342 fPosPrefixPattern = new UnicodeString();
michael@0 5343 /* test for NULL */
michael@0 5344 if (fPosPrefixPattern == 0) {
michael@0 5345 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5346 return;
michael@0 5347 }
michael@0 5348 }
michael@0 5349 if (fPosSuffixPattern != NULL) {
michael@0 5350 fPosSuffixPattern->remove();
michael@0 5351 } else {
michael@0 5352 fPosSuffixPattern = new UnicodeString();
michael@0 5353 /* test for NULL */
michael@0 5354 if (fPosSuffixPattern == 0) {
michael@0 5355 delete fPosPrefixPattern;
michael@0 5356 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5357 return;
michael@0 5358 }
michael@0 5359 }
michael@0 5360
michael@0 5361 setMinimumIntegerDigits(0);
michael@0 5362 setMaximumIntegerDigits(kDoubleIntegerDigits);
michael@0 5363 setMinimumFractionDigits(0);
michael@0 5364 setMaximumFractionDigits(kDoubleFractionDigits);
michael@0 5365
michael@0 5366 fUseExponentialNotation = FALSE;
michael@0 5367 fCurrencySignCount = fgCurrencySignCountZero;
michael@0 5368 setGroupingUsed(FALSE);
michael@0 5369 fGroupingSize = 0;
michael@0 5370 fGroupingSize2 = 0;
michael@0 5371 setMultiplier(1);
michael@0 5372 setDecimalSeparatorAlwaysShown(FALSE);
michael@0 5373 fFormatWidth = 0;
michael@0 5374 setRoundingIncrement(0.0);
michael@0 5375 }
michael@0 5376
michael@0 5377 // If there was no negative pattern, or if the negative pattern is
michael@0 5378 // identical to the positive pattern, then prepend the minus sign to the
michael@0 5379 // positive pattern to form the negative pattern.
michael@0 5380 if (fNegPrefixPattern == NULL ||
michael@0 5381 (*fNegPrefixPattern == *fPosPrefixPattern
michael@0 5382 && *fNegSuffixPattern == *fPosSuffixPattern)) {
michael@0 5383 _copy_ptr(&fNegSuffixPattern, fPosSuffixPattern);
michael@0 5384 if (fNegPrefixPattern == NULL) {
michael@0 5385 fNegPrefixPattern = new UnicodeString();
michael@0 5386 /* test for NULL */
michael@0 5387 if (fNegPrefixPattern == 0) {
michael@0 5388 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5389 return;
michael@0 5390 }
michael@0 5391 } else {
michael@0 5392 fNegPrefixPattern->remove();
michael@0 5393 }
michael@0 5394 fNegPrefixPattern->append(kQuote).append(kPatternMinus)
michael@0 5395 .append(*fPosPrefixPattern);
michael@0 5396 }
michael@0 5397 #ifdef FMT_DEBUG
michael@0 5398 UnicodeString s;
michael@0 5399 s.append((UnicodeString)"\"").append(pattern).append((UnicodeString)"\"->");
michael@0 5400 debugout(s);
michael@0 5401 #endif
michael@0 5402
michael@0 5403 // save the pattern
michael@0 5404 fFormatPattern = pattern;
michael@0 5405 }
michael@0 5406
michael@0 5407
michael@0 5408 void
michael@0 5409 DecimalFormat::expandAffixAdjustWidth(const UnicodeString* pluralCount) {
michael@0 5410 expandAffixes(pluralCount);
michael@0 5411 if (fFormatWidth > 0) {
michael@0 5412 // Finish computing format width (see above)
michael@0 5413 // TODO: how to handle fFormatWidth,
michael@0 5414 // need to save in f(Plural)AffixesForCurrecy?
michael@0 5415 fFormatWidth += fPositivePrefix.length() + fPositiveSuffix.length();
michael@0 5416 }
michael@0 5417 }
michael@0 5418
michael@0 5419
michael@0 5420 void
michael@0 5421 DecimalFormat::applyPattern(const UnicodeString& pattern,
michael@0 5422 UBool localized,
michael@0 5423 UParseError& parseError,
michael@0 5424 UErrorCode& status)
michael@0 5425 {
michael@0 5426 // do the following re-set first. since they change private data by
michael@0 5427 // apply pattern again.
michael@0 5428 if (pattern.indexOf(kCurrencySign) != -1) {
michael@0 5429 if (fCurrencyPluralInfo == NULL) {
michael@0 5430 // initialize currencyPluralInfo if needed
michael@0 5431 fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), status);
michael@0 5432 }
michael@0 5433 if (fAffixPatternsForCurrency == NULL) {
michael@0 5434 setupCurrencyAffixPatterns(status);
michael@0 5435 }
michael@0 5436 if (pattern.indexOf(fgTripleCurrencySign, 3, 0) != -1) {
michael@0 5437 // only setup the affixes of the current pattern.
michael@0 5438 setupCurrencyAffixes(pattern, TRUE, FALSE, status);
michael@0 5439 }
michael@0 5440 }
michael@0 5441 applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
michael@0 5442 expandAffixAdjustWidth(NULL);
michael@0 5443 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5444 handleChanged();
michael@0 5445 #endif
michael@0 5446 }
michael@0 5447
michael@0 5448
michael@0 5449 void
michael@0 5450 DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount,
michael@0 5451 const UnicodeString& pattern,
michael@0 5452 UBool localized,
michael@0 5453 UParseError& parseError,
michael@0 5454 UErrorCode& status) {
michael@0 5455 applyPatternWithoutExpandAffix(pattern, localized, parseError, status);
michael@0 5456 expandAffixAdjustWidth(&pluralCount);
michael@0 5457 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5458 handleChanged();
michael@0 5459 #endif
michael@0 5460 }
michael@0 5461
michael@0 5462
michael@0 5463 /**
michael@0 5464 * Sets the maximum number of digits allowed in the integer portion of a
michael@0 5465 * number.
michael@0 5466 * @see NumberFormat#setMaximumIntegerDigits
michael@0 5467 */
michael@0 5468 void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {
michael@0 5469 NumberFormat::setMaximumIntegerDigits(_min(newValue, gDefaultMaxIntegerDigits));
michael@0 5470 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5471 handleChanged();
michael@0 5472 #endif
michael@0 5473 }
michael@0 5474
michael@0 5475 /**
michael@0 5476 * Sets the minimum number of digits allowed in the integer portion of a
michael@0 5477 * number. This override limits the integer digit count to 309.
michael@0 5478 * @see NumberFormat#setMinimumIntegerDigits
michael@0 5479 */
michael@0 5480 void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {
michael@0 5481 NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits));
michael@0 5482 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5483 handleChanged();
michael@0 5484 #endif
michael@0 5485 }
michael@0 5486
michael@0 5487 /**
michael@0 5488 * Sets the maximum number of digits allowed in the fraction portion of a
michael@0 5489 * number. This override limits the fraction digit count to 340.
michael@0 5490 * @see NumberFormat#setMaximumFractionDigits
michael@0 5491 */
michael@0 5492 void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {
michael@0 5493 NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits));
michael@0 5494 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5495 handleChanged();
michael@0 5496 #endif
michael@0 5497 }
michael@0 5498
michael@0 5499 /**
michael@0 5500 * Sets the minimum number of digits allowed in the fraction portion of a
michael@0 5501 * number. This override limits the fraction digit count to 340.
michael@0 5502 * @see NumberFormat#setMinimumFractionDigits
michael@0 5503 */
michael@0 5504 void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {
michael@0 5505 NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits));
michael@0 5506 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5507 handleChanged();
michael@0 5508 #endif
michael@0 5509 }
michael@0 5510
michael@0 5511 int32_t DecimalFormat::getMinimumSignificantDigits() const {
michael@0 5512 return fMinSignificantDigits;
michael@0 5513 }
michael@0 5514
michael@0 5515 int32_t DecimalFormat::getMaximumSignificantDigits() const {
michael@0 5516 return fMaxSignificantDigits;
michael@0 5517 }
michael@0 5518
michael@0 5519 void DecimalFormat::setMinimumSignificantDigits(int32_t min) {
michael@0 5520 if (min < 1) {
michael@0 5521 min = 1;
michael@0 5522 }
michael@0 5523 // pin max sig dig to >= min
michael@0 5524 int32_t max = _max(fMaxSignificantDigits, min);
michael@0 5525 fMinSignificantDigits = min;
michael@0 5526 fMaxSignificantDigits = max;
michael@0 5527 fUseSignificantDigits = TRUE;
michael@0 5528 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5529 handleChanged();
michael@0 5530 #endif
michael@0 5531 }
michael@0 5532
michael@0 5533 void DecimalFormat::setMaximumSignificantDigits(int32_t max) {
michael@0 5534 if (max < 1) {
michael@0 5535 max = 1;
michael@0 5536 }
michael@0 5537 // pin min sig dig to 1..max
michael@0 5538 U_ASSERT(fMinSignificantDigits >= 1);
michael@0 5539 int32_t min = _min(fMinSignificantDigits, max);
michael@0 5540 fMinSignificantDigits = min;
michael@0 5541 fMaxSignificantDigits = max;
michael@0 5542 fUseSignificantDigits = TRUE;
michael@0 5543 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5544 handleChanged();
michael@0 5545 #endif
michael@0 5546 }
michael@0 5547
michael@0 5548 UBool DecimalFormat::areSignificantDigitsUsed() const {
michael@0 5549 return fUseSignificantDigits;
michael@0 5550 }
michael@0 5551
michael@0 5552 void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
michael@0 5553 fUseSignificantDigits = useSignificantDigits;
michael@0 5554 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5555 handleChanged();
michael@0 5556 #endif
michael@0 5557 }
michael@0 5558
michael@0 5559 void DecimalFormat::setCurrencyInternally(const UChar* theCurrency,
michael@0 5560 UErrorCode& ec) {
michael@0 5561 // If we are a currency format, then modify our affixes to
michael@0 5562 // encode the currency symbol for the given currency in our
michael@0 5563 // locale, and adjust the decimal digits and rounding for the
michael@0 5564 // given currency.
michael@0 5565
michael@0 5566 // Note: The code is ordered so that this object is *not changed*
michael@0 5567 // until we are sure we are going to succeed.
michael@0 5568
michael@0 5569 // NULL or empty currency is *legal* and indicates no currency.
michael@0 5570 UBool isCurr = (theCurrency && *theCurrency);
michael@0 5571
michael@0 5572 double rounding = 0.0;
michael@0 5573 int32_t frac = 0;
michael@0 5574 if (fCurrencySignCount != fgCurrencySignCountZero && isCurr) {
michael@0 5575 rounding = ucurr_getRoundingIncrement(theCurrency, &ec);
michael@0 5576 frac = ucurr_getDefaultFractionDigits(theCurrency, &ec);
michael@0 5577 }
michael@0 5578
michael@0 5579 NumberFormat::setCurrency(theCurrency, ec);
michael@0 5580 if (U_FAILURE(ec)) return;
michael@0 5581
michael@0 5582 if (fCurrencySignCount != fgCurrencySignCountZero) {
michael@0 5583 // NULL or empty currency is *legal* and indicates no currency.
michael@0 5584 if (isCurr) {
michael@0 5585 setRoundingIncrement(rounding);
michael@0 5586 setMinimumFractionDigits(frac);
michael@0 5587 setMaximumFractionDigits(frac);
michael@0 5588 }
michael@0 5589 expandAffixes(NULL);
michael@0 5590 }
michael@0 5591 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5592 handleChanged();
michael@0 5593 #endif
michael@0 5594 }
michael@0 5595
michael@0 5596 void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) {
michael@0 5597 // set the currency before compute affixes to get the right currency names
michael@0 5598 NumberFormat::setCurrency(theCurrency, ec);
michael@0 5599 if (fFormatPattern.indexOf(fgTripleCurrencySign, 3, 0) != -1) {
michael@0 5600 UnicodeString savedPtn = fFormatPattern;
michael@0 5601 setupCurrencyAffixes(fFormatPattern, TRUE, TRUE, ec);
michael@0 5602 UParseError parseErr;
michael@0 5603 applyPattern(savedPtn, FALSE, parseErr, ec);
michael@0 5604 }
michael@0 5605 // set the currency after apply pattern to get the correct rounding/fraction
michael@0 5606 setCurrencyInternally(theCurrency, ec);
michael@0 5607 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5608 handleChanged();
michael@0 5609 #endif
michael@0 5610 }
michael@0 5611
michael@0 5612 // Deprecated variant with no UErrorCode parameter
michael@0 5613 void DecimalFormat::setCurrency(const UChar* theCurrency) {
michael@0 5614 UErrorCode ec = U_ZERO_ERROR;
michael@0 5615 setCurrency(theCurrency, ec);
michael@0 5616 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5617 handleChanged();
michael@0 5618 #endif
michael@0 5619 }
michael@0 5620
michael@0 5621 void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const {
michael@0 5622 if (fSymbols == NULL) {
michael@0 5623 ec = U_MEMORY_ALLOCATION_ERROR;
michael@0 5624 return;
michael@0 5625 }
michael@0 5626 ec = U_ZERO_ERROR;
michael@0 5627 const UChar* c = getCurrency();
michael@0 5628 if (*c == 0) {
michael@0 5629 const UnicodeString &intl =
michael@0 5630 fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol);
michael@0 5631 c = intl.getBuffer(); // ok for intl to go out of scope
michael@0 5632 }
michael@0 5633 u_strncpy(result, c, 3);
michael@0 5634 result[3] = 0;
michael@0 5635 }
michael@0 5636
michael@0 5637 /**
michael@0 5638 * Return the number of fraction digits to display, or the total
michael@0 5639 * number of digits for significant digit formats and exponential
michael@0 5640 * formats.
michael@0 5641 */
michael@0 5642 int32_t
michael@0 5643 DecimalFormat::precision() const {
michael@0 5644 if (areSignificantDigitsUsed()) {
michael@0 5645 return getMaximumSignificantDigits();
michael@0 5646 } else if (fUseExponentialNotation) {
michael@0 5647 return getMinimumIntegerDigits() + getMaximumFractionDigits();
michael@0 5648 } else {
michael@0 5649 return getMaximumFractionDigits();
michael@0 5650 }
michael@0 5651 }
michael@0 5652
michael@0 5653
michael@0 5654 // TODO: template algorithm
michael@0 5655 Hashtable*
michael@0 5656 DecimalFormat::initHashForAffix(UErrorCode& status) {
michael@0 5657 if ( U_FAILURE(status) ) {
michael@0 5658 return NULL;
michael@0 5659 }
michael@0 5660 Hashtable* hTable;
michael@0 5661 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
michael@0 5662 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5663 return NULL;
michael@0 5664 }
michael@0 5665 if ( U_FAILURE(status) ) {
michael@0 5666 delete hTable;
michael@0 5667 return NULL;
michael@0 5668 }
michael@0 5669 hTable->setValueComparator(decimfmtAffixValueComparator);
michael@0 5670 return hTable;
michael@0 5671 }
michael@0 5672
michael@0 5673 Hashtable*
michael@0 5674 DecimalFormat::initHashForAffixPattern(UErrorCode& status) {
michael@0 5675 if ( U_FAILURE(status) ) {
michael@0 5676 return NULL;
michael@0 5677 }
michael@0 5678 Hashtable* hTable;
michael@0 5679 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) {
michael@0 5680 status = U_MEMORY_ALLOCATION_ERROR;
michael@0 5681 return NULL;
michael@0 5682 }
michael@0 5683 if ( U_FAILURE(status) ) {
michael@0 5684 delete hTable;
michael@0 5685 return NULL;
michael@0 5686 }
michael@0 5687 hTable->setValueComparator(decimfmtAffixPatternValueComparator);
michael@0 5688 return hTable;
michael@0 5689 }
michael@0 5690
michael@0 5691 void
michael@0 5692 DecimalFormat::deleteHashForAffix(Hashtable*& table)
michael@0 5693 {
michael@0 5694 if ( table == NULL ) {
michael@0 5695 return;
michael@0 5696 }
michael@0 5697 int32_t pos = -1;
michael@0 5698 const UHashElement* element = NULL;
michael@0 5699 while ( (element = table->nextElement(pos)) != NULL ) {
michael@0 5700 const UHashTok valueTok = element->value;
michael@0 5701 const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer;
michael@0 5702 delete value;
michael@0 5703 }
michael@0 5704 delete table;
michael@0 5705 table = NULL;
michael@0 5706 }
michael@0 5707
michael@0 5708
michael@0 5709
michael@0 5710 void
michael@0 5711 DecimalFormat::deleteHashForAffixPattern()
michael@0 5712 {
michael@0 5713 if ( fAffixPatternsForCurrency == NULL ) {
michael@0 5714 return;
michael@0 5715 }
michael@0 5716 int32_t pos = -1;
michael@0 5717 const UHashElement* element = NULL;
michael@0 5718 while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) {
michael@0 5719 const UHashTok valueTok = element->value;
michael@0 5720 const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
michael@0 5721 delete value;
michael@0 5722 }
michael@0 5723 delete fAffixPatternsForCurrency;
michael@0 5724 fAffixPatternsForCurrency = NULL;
michael@0 5725 }
michael@0 5726
michael@0 5727
michael@0 5728 void
michael@0 5729 DecimalFormat::copyHashForAffixPattern(const Hashtable* source,
michael@0 5730 Hashtable* target,
michael@0 5731 UErrorCode& status) {
michael@0 5732 if ( U_FAILURE(status) ) {
michael@0 5733 return;
michael@0 5734 }
michael@0 5735 int32_t pos = -1;
michael@0 5736 const UHashElement* element = NULL;
michael@0 5737 if ( source ) {
michael@0 5738 while ( (element = source->nextElement(pos)) != NULL ) {
michael@0 5739 const UHashTok keyTok = element->key;
michael@0 5740 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
michael@0 5741 const UHashTok valueTok = element->value;
michael@0 5742 const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)valueTok.pointer;
michael@0 5743 AffixPatternsForCurrency* copy = new AffixPatternsForCurrency(
michael@0 5744 value->negPrefixPatternForCurrency,
michael@0 5745 value->negSuffixPatternForCurrency,
michael@0 5746 value->posPrefixPatternForCurrency,
michael@0 5747 value->posSuffixPatternForCurrency,
michael@0 5748 value->patternType);
michael@0 5749 target->put(UnicodeString(*key), copy, status);
michael@0 5750 if ( U_FAILURE(status) ) {
michael@0 5751 return;
michael@0 5752 }
michael@0 5753 }
michael@0 5754 }
michael@0 5755 }
michael@0 5756
michael@0 5757 DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
michael@0 5758 int32_t newValue,
michael@0 5759 UErrorCode &status) {
michael@0 5760 if(U_FAILURE(status)) return *this;
michael@0 5761
michael@0 5762 switch(attr) {
michael@0 5763 case UNUM_LENIENT_PARSE:
michael@0 5764 setLenient(newValue!=0);
michael@0 5765 break;
michael@0 5766
michael@0 5767 case UNUM_PARSE_INT_ONLY:
michael@0 5768 setParseIntegerOnly(newValue!=0);
michael@0 5769 break;
michael@0 5770
michael@0 5771 case UNUM_GROUPING_USED:
michael@0 5772 setGroupingUsed(newValue!=0);
michael@0 5773 break;
michael@0 5774
michael@0 5775 case UNUM_DECIMAL_ALWAYS_SHOWN:
michael@0 5776 setDecimalSeparatorAlwaysShown(newValue!=0);
michael@0 5777 break;
michael@0 5778
michael@0 5779 case UNUM_MAX_INTEGER_DIGITS:
michael@0 5780 setMaximumIntegerDigits(newValue);
michael@0 5781 break;
michael@0 5782
michael@0 5783 case UNUM_MIN_INTEGER_DIGITS:
michael@0 5784 setMinimumIntegerDigits(newValue);
michael@0 5785 break;
michael@0 5786
michael@0 5787 case UNUM_INTEGER_DIGITS:
michael@0 5788 setMinimumIntegerDigits(newValue);
michael@0 5789 setMaximumIntegerDigits(newValue);
michael@0 5790 break;
michael@0 5791
michael@0 5792 case UNUM_MAX_FRACTION_DIGITS:
michael@0 5793 setMaximumFractionDigits(newValue);
michael@0 5794 break;
michael@0 5795
michael@0 5796 case UNUM_MIN_FRACTION_DIGITS:
michael@0 5797 setMinimumFractionDigits(newValue);
michael@0 5798 break;
michael@0 5799
michael@0 5800 case UNUM_FRACTION_DIGITS:
michael@0 5801 setMinimumFractionDigits(newValue);
michael@0 5802 setMaximumFractionDigits(newValue);
michael@0 5803 break;
michael@0 5804
michael@0 5805 case UNUM_SIGNIFICANT_DIGITS_USED:
michael@0 5806 setSignificantDigitsUsed(newValue!=0);
michael@0 5807 break;
michael@0 5808
michael@0 5809 case UNUM_MAX_SIGNIFICANT_DIGITS:
michael@0 5810 setMaximumSignificantDigits(newValue);
michael@0 5811 break;
michael@0 5812
michael@0 5813 case UNUM_MIN_SIGNIFICANT_DIGITS:
michael@0 5814 setMinimumSignificantDigits(newValue);
michael@0 5815 break;
michael@0 5816
michael@0 5817 case UNUM_MULTIPLIER:
michael@0 5818 setMultiplier(newValue);
michael@0 5819 break;
michael@0 5820
michael@0 5821 case UNUM_GROUPING_SIZE:
michael@0 5822 setGroupingSize(newValue);
michael@0 5823 break;
michael@0 5824
michael@0 5825 case UNUM_ROUNDING_MODE:
michael@0 5826 setRoundingMode((DecimalFormat::ERoundingMode)newValue);
michael@0 5827 break;
michael@0 5828
michael@0 5829 case UNUM_FORMAT_WIDTH:
michael@0 5830 setFormatWidth(newValue);
michael@0 5831 break;
michael@0 5832
michael@0 5833 case UNUM_PADDING_POSITION:
michael@0 5834 /** The position at which padding will take place. */
michael@0 5835 setPadPosition((DecimalFormat::EPadPosition)newValue);
michael@0 5836 break;
michael@0 5837
michael@0 5838 case UNUM_SECONDARY_GROUPING_SIZE:
michael@0 5839 setSecondaryGroupingSize(newValue);
michael@0 5840 break;
michael@0 5841
michael@0 5842 #if UCONFIG_HAVE_PARSEALLINPUT
michael@0 5843 case UNUM_PARSE_ALL_INPUT:
michael@0 5844 setParseAllInput((UNumberFormatAttributeValue)newValue);
michael@0 5845 break;
michael@0 5846 #endif
michael@0 5847
michael@0 5848 /* These are stored in fBoolFlags */
michael@0 5849 case UNUM_PARSE_NO_EXPONENT:
michael@0 5850 case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
michael@0 5851 if(!fBoolFlags.isValidValue(newValue)) {
michael@0 5852 status = U_ILLEGAL_ARGUMENT_ERROR;
michael@0 5853 } else {
michael@0 5854 fBoolFlags.set(attr, newValue);
michael@0 5855 }
michael@0 5856 break;
michael@0 5857
michael@0 5858 case UNUM_SCALE:
michael@0 5859 fScale = newValue;
michael@0 5860 break;
michael@0 5861
michael@0 5862 default:
michael@0 5863 status = U_UNSUPPORTED_ERROR;
michael@0 5864 break;
michael@0 5865 }
michael@0 5866 return *this;
michael@0 5867 }
michael@0 5868
michael@0 5869 int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
michael@0 5870 UErrorCode &status ) const {
michael@0 5871 if(U_FAILURE(status)) return -1;
michael@0 5872 switch(attr) {
michael@0 5873 case UNUM_LENIENT_PARSE:
michael@0 5874 return isLenient();
michael@0 5875
michael@0 5876 case UNUM_PARSE_INT_ONLY:
michael@0 5877 return isParseIntegerOnly();
michael@0 5878
michael@0 5879 case UNUM_GROUPING_USED:
michael@0 5880 return isGroupingUsed();
michael@0 5881
michael@0 5882 case UNUM_DECIMAL_ALWAYS_SHOWN:
michael@0 5883 return isDecimalSeparatorAlwaysShown();
michael@0 5884
michael@0 5885 case UNUM_MAX_INTEGER_DIGITS:
michael@0 5886 return getMaximumIntegerDigits();
michael@0 5887
michael@0 5888 case UNUM_MIN_INTEGER_DIGITS:
michael@0 5889 return getMinimumIntegerDigits();
michael@0 5890
michael@0 5891 case UNUM_INTEGER_DIGITS:
michael@0 5892 // TBD: what should this return?
michael@0 5893 return getMinimumIntegerDigits();
michael@0 5894
michael@0 5895 case UNUM_MAX_FRACTION_DIGITS:
michael@0 5896 return getMaximumFractionDigits();
michael@0 5897
michael@0 5898 case UNUM_MIN_FRACTION_DIGITS:
michael@0 5899 return getMinimumFractionDigits();
michael@0 5900
michael@0 5901 case UNUM_FRACTION_DIGITS:
michael@0 5902 // TBD: what should this return?
michael@0 5903 return getMinimumFractionDigits();
michael@0 5904
michael@0 5905 case UNUM_SIGNIFICANT_DIGITS_USED:
michael@0 5906 return areSignificantDigitsUsed();
michael@0 5907
michael@0 5908 case UNUM_MAX_SIGNIFICANT_DIGITS:
michael@0 5909 return getMaximumSignificantDigits();
michael@0 5910
michael@0 5911 case UNUM_MIN_SIGNIFICANT_DIGITS:
michael@0 5912 return getMinimumSignificantDigits();
michael@0 5913
michael@0 5914 case UNUM_MULTIPLIER:
michael@0 5915 return getMultiplier();
michael@0 5916
michael@0 5917 case UNUM_GROUPING_SIZE:
michael@0 5918 return getGroupingSize();
michael@0 5919
michael@0 5920 case UNUM_ROUNDING_MODE:
michael@0 5921 return getRoundingMode();
michael@0 5922
michael@0 5923 case UNUM_FORMAT_WIDTH:
michael@0 5924 return getFormatWidth();
michael@0 5925
michael@0 5926 case UNUM_PADDING_POSITION:
michael@0 5927 return getPadPosition();
michael@0 5928
michael@0 5929 case UNUM_SECONDARY_GROUPING_SIZE:
michael@0 5930 return getSecondaryGroupingSize();
michael@0 5931
michael@0 5932 /* These are stored in fBoolFlags */
michael@0 5933 case UNUM_PARSE_NO_EXPONENT:
michael@0 5934 case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
michael@0 5935 return fBoolFlags.get(attr);
michael@0 5936
michael@0 5937 case UNUM_SCALE:
michael@0 5938 return fScale;
michael@0 5939
michael@0 5940 default:
michael@0 5941 status = U_UNSUPPORTED_ERROR;
michael@0 5942 break;
michael@0 5943 }
michael@0 5944
michael@0 5945 return -1; /* undefined */
michael@0 5946 }
michael@0 5947
michael@0 5948 #if UCONFIG_HAVE_PARSEALLINPUT
michael@0 5949 void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {
michael@0 5950 fParseAllInput = value;
michael@0 5951 #if UCONFIG_FORMAT_FASTPATHS_49
michael@0 5952 handleChanged();
michael@0 5953 #endif
michael@0 5954 }
michael@0 5955 #endif
michael@0 5956
michael@0 5957 void
michael@0 5958 DecimalFormat::copyHashForAffix(const Hashtable* source,
michael@0 5959 Hashtable* target,
michael@0 5960 UErrorCode& status) {
michael@0 5961 if ( U_FAILURE(status) ) {
michael@0 5962 return;
michael@0 5963 }
michael@0 5964 int32_t pos = -1;
michael@0 5965 const UHashElement* element = NULL;
michael@0 5966 if ( source ) {
michael@0 5967 while ( (element = source->nextElement(pos)) != NULL ) {
michael@0 5968 const UHashTok keyTok = element->key;
michael@0 5969 const UnicodeString* key = (UnicodeString*)keyTok.pointer;
michael@0 5970
michael@0 5971 const UHashTok valueTok = element->value;
michael@0 5972 const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer;
michael@0 5973 AffixesForCurrency* copy = new AffixesForCurrency(
michael@0 5974 value->negPrefixForCurrency,
michael@0 5975 value->negSuffixForCurrency,
michael@0 5976 value->posPrefixForCurrency,
michael@0 5977 value->posSuffixForCurrency);
michael@0 5978 target->put(UnicodeString(*key), copy, status);
michael@0 5979 if ( U_FAILURE(status) ) {
michael@0 5980 return;
michael@0 5981 }
michael@0 5982 }
michael@0 5983 }
michael@0 5984 }
michael@0 5985
michael@0 5986 U_NAMESPACE_END
michael@0 5987
michael@0 5988 #endif /* #if !UCONFIG_NO_FORMATTING */
michael@0 5989
michael@0 5990 //eof

mercurial