OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ******************************************************************************* |
| 3 * Copyright (C) 1997-2010, International Business Machines Corporation and * |
| 4 * others. All Rights Reserved. * |
| 5 ******************************************************************************* |
| 6 * |
| 7 * File DECIMFMT.CPP |
| 8 * |
| 9 * Modification History: |
| 10 * |
| 11 * Date Name Description |
| 12 * 02/19/97 aliu Converted from java. |
| 13 * 03/20/97 clhuang Implemented with new APIs. |
| 14 * 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it. |
| 15 * 04/3/97 aliu Rewrote parsing and formatting completely, and |
| 16 * cleaned up and debugged. Actually works now. |
| 17 * Implemented NAN and INF handling, for both parsing |
| 18 * and formatting. Extensive testing & debugging. |
| 19 * 04/10/97 aliu Modified to compile on AIX. |
| 20 * 04/16/97 aliu Rewrote to use DigitList, which has been resurrected
. |
| 21 * Changed DigitCount to int per code review. |
| 22 * 07/09/97 helena Made ParsePosition into a class. |
| 23 * 08/26/97 aliu Extensive changes to applyPattern; completely |
| 24 * rewritten from the Java. |
| 25 * 09/09/97 aliu Ported over support for exponential formats. |
| 26 * 07/20/98 stephen JDK 1.2 sync up. |
| 27 * Various instances of '0' replaced with 'NULL' |
| 28 * Check for grouping size in subFormat() |
| 29 * Brought subParse() in line with Java 1.2 |
| 30 * Added method appendAffix() |
| 31 * 08/24/1998 srl Removed Mutex calls. This is not a thread safe class
! |
| 32 * 02/22/99 stephen Removed character literals for EBCDIC safety |
| 33 * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixe
s |
| 34 * 06/28/99 stephen Fixed bugs in toPattern(). |
| 35 * 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad, |
| 36 * fPadPosition |
| 37 ******************************************************************************** |
| 38 */ |
| 39 |
| 40 #include "unicode/utypes.h" |
| 41 |
| 42 #if !UCONFIG_NO_FORMATTING |
| 43 |
| 44 #include "fphdlimp.h" |
| 45 #include "unicode/decimfmt.h" |
| 46 #include "unicode/choicfmt.h" |
| 47 #include "unicode/ucurr.h" |
| 48 #include "unicode/ustring.h" |
| 49 #include "unicode/dcfmtsym.h" |
| 50 #include "unicode/ures.h" |
| 51 #include "unicode/uchar.h" |
| 52 #include "unicode/curramt.h" |
| 53 #include "unicode/currpinf.h" |
| 54 #include "unicode/plurrule.h" |
| 55 #include "ucurrimp.h" |
| 56 #include "charstr.h" |
| 57 #include "cmemory.h" |
| 58 #include "util.h" |
| 59 #include "digitlst.h" |
| 60 #include "cstring.h" |
| 61 #include "umutex.h" |
| 62 #include "uassert.h" |
| 63 #include "putilimp.h" |
| 64 #include <math.h> |
| 65 #include "hash.h" |
| 66 |
| 67 |
| 68 U_NAMESPACE_BEGIN |
| 69 |
| 70 /* For currency parsing purose, |
| 71 * Need to remember all prefix patterns and suffix patterns of |
| 72 * every currency format pattern, |
| 73 * including the pattern of default currecny style |
| 74 * and plural currency style. And the patterns are set through applyPattern. |
| 75 */ |
| 76 struct AffixPatternsForCurrency : public UMemory { |
| 77 // negative prefix pattern |
| 78 UnicodeString negPrefixPatternForCurrency; |
| 79 // negative suffix pattern |
| 80 UnicodeString negSuffixPatternForCurrency; |
| 81 // positive prefix pattern |
| 82 UnicodeString posPrefixPatternForCurrency; |
| 83 // positive suffix pattern |
| 84 UnicodeString posSuffixPatternForCurrency; |
| 85 int8_t patternType; |
| 86 |
| 87 AffixPatternsForCurrency(const UnicodeString& negPrefix, |
| 88 const UnicodeString& ne
gSuffix, |
| 89 const UnicodeString& po
sPrefix, |
| 90 const UnicodeString& po
sSuffix, |
| 91 int8_t type) { |
| 92 negPrefixPatternForCurrency = negPrefix; |
| 93 negSuffixPatternForCurrency = negSuffix; |
| 94 posPrefixPatternForCurrency = posPrefix; |
| 95 posSuffixPatternForCurrency = posSuffix; |
| 96 patternType = type; |
| 97 } |
| 98 }; |
| 99 |
| 100 /* affix for currency formatting when the currency sign in the pattern |
| 101 * equals to 3, such as the pattern contains 3 currency sign or |
| 102 * the formatter style is currency plural format style. |
| 103 */ |
| 104 struct AffixesForCurrency : public UMemory { |
| 105 // negative prefix |
| 106 UnicodeString negPrefixForCurrency; |
| 107 // negative suffix |
| 108 UnicodeString negSuffixForCurrency; |
| 109 // positive prefix |
| 110 UnicodeString posPrefixForCurrency; |
| 111 // positive suffix |
| 112 UnicodeString posSuffixForCurrency; |
| 113 |
| 114 int32_t formatWidth; |
| 115 |
| 116 AffixesForCurrency(const UnicodeString& negPrefix, |
| 117 const UnicodeString& negSuffix, |
| 118 const UnicodeString& posPrefix, |
| 119 const UnicodeString& posSuffix) { |
| 120 negPrefixForCurrency = negPrefix; |
| 121 negSuffixForCurrency = negSuffix; |
| 122 posPrefixForCurrency = posPrefix; |
| 123 posSuffixForCurrency = posSuffix; |
| 124 } |
| 125 }; |
| 126 |
| 127 U_CDECL_BEGIN |
| 128 |
| 129 /** |
| 130 * @internal ICU 4.2 |
| 131 */ |
| 132 static UBool U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val
2); |
| 133 |
| 134 /** |
| 135 * @internal ICU 4.2 |
| 136 */ |
| 137 static UBool U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHash
Tok val2); |
| 138 |
| 139 |
| 140 static UBool |
| 141 U_CALLCONV decimfmtAffixValueComparator(UHashTok val1, UHashTok val2) { |
| 142 const AffixesForCurrency* affix_1 = |
| 143 (AffixesForCurrency*)val1.pointer; |
| 144 const AffixesForCurrency* affix_2 = |
| 145 (AffixesForCurrency*)val2.pointer; |
| 146 return affix_1->negPrefixForCurrency == affix_2->negPrefixForCurrency && |
| 147 affix_1->negSuffixForCurrency == affix_2->negSuffixForCurrency && |
| 148 affix_1->posPrefixForCurrency == affix_2->posPrefixForCurrency && |
| 149 affix_1->posSuffixForCurrency == affix_2->posSuffixForCurrency; |
| 150 } |
| 151 |
| 152 |
| 153 static UBool |
| 154 U_CALLCONV decimfmtAffixPatternValueComparator(UHashTok val1, UHashTok val2) { |
| 155 const AffixPatternsForCurrency* affix_1 = |
| 156 (AffixPatternsForCurrency*)val1.pointer; |
| 157 const AffixPatternsForCurrency* affix_2 = |
| 158 (AffixPatternsForCurrency*)val2.pointer; |
| 159 return affix_1->negPrefixPatternForCurrency == |
| 160 affix_2->negPrefixPatternForCurrency && |
| 161 affix_1->negSuffixPatternForCurrency == |
| 162 affix_2->negSuffixPatternForCurrency && |
| 163 affix_1->posPrefixPatternForCurrency == |
| 164 affix_2->posPrefixPatternForCurrency && |
| 165 affix_1->posSuffixPatternForCurrency == |
| 166 affix_2->posSuffixPatternForCurrency && |
| 167 affix_1->patternType == affix_2->patternType; |
| 168 } |
| 169 |
| 170 U_CDECL_END |
| 171 |
| 172 |
| 173 //#define FMT_DEBUG |
| 174 |
| 175 #ifdef FMT_DEBUG |
| 176 #include <stdio.h> |
| 177 static void debugout(UnicodeString s) { |
| 178 char buf[2000]; |
| 179 s.extract((int32_t) 0, s.length(), buf); |
| 180 printf("%s\n", buf); |
| 181 } |
| 182 #define debug(x) printf("%s\n", x); |
| 183 #else |
| 184 #define debugout(x) |
| 185 #define debug(x) |
| 186 #endif |
| 187 |
| 188 |
| 189 |
| 190 // ***************************************************************************** |
| 191 // class DecimalFormat |
| 192 // ***************************************************************************** |
| 193 |
| 194 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat) |
| 195 |
| 196 // Constants for characters used in programmatic (unlocalized) patterns. |
| 197 #define kPatternZeroDigit ((UChar)0x0030) /*'0'*/ |
| 198 #define kPatternSignificantDigit ((UChar)0x0040) /*'@'*/ |
| 199 #define kPatternGroupingSeparator ((UChar)0x002C) /*','*/ |
| 200 #define kPatternDecimalSeparator ((UChar)0x002E) /*'.'*/ |
| 201 #define kPatternPerMill ((UChar)0x2030) |
| 202 #define kPatternPercent ((UChar)0x0025) /*'%'*/ |
| 203 #define kPatternDigit ((UChar)0x0023) /*'#'*/ |
| 204 #define kPatternSeparator ((UChar)0x003B) /*';'*/ |
| 205 #define kPatternExponent ((UChar)0x0045) /*'E'*/ |
| 206 #define kPatternPlus ((UChar)0x002B) /*'+'*/ |
| 207 #define kPatternMinus ((UChar)0x002D) /*'-'*/ |
| 208 #define kPatternPadEscape ((UChar)0x002A) /*'*'*/ |
| 209 #define kQuote ((UChar)0x0027) /*'\''*/ |
| 210 /** |
| 211 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It |
| 212 * is used in patterns and substitued with either the currency symbol, |
| 213 * or if it is doubled, with the international currency symbol. If the |
| 214 * CURRENCY_SIGN is seen in a pattern, then the decimal separator is |
| 215 * replaced with the monetary decimal separator. |
| 216 */ |
| 217 #define kCurrencySign ((UChar)0x00A4) |
| 218 #define kDefaultPad ((UChar)0x0020) /* */ |
| 219 |
| 220 const int32_t DecimalFormat::kDoubleIntegerDigits = 309; |
| 221 const int32_t DecimalFormat::kDoubleFractionDigits = 340; |
| 222 |
| 223 const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8; |
| 224 |
| 225 /** |
| 226 * These are the tags we expect to see in normal resource bundle files associate
d |
| 227 * with a locale. |
| 228 */ |
| 229 const char DecimalFormat::fgNumberPatterns[]="NumberPatterns"; // Deprecated - n
ot used |
| 230 static const char fgNumberElements[]="NumberElements"; |
| 231 static const char fgLatn[]="latn"; |
| 232 static const char fgPatterns[]="patterns"; |
| 233 static const char fgDecimalFormat[]="decimalFormat"; |
| 234 static const char fgCurrencyFormat[]="currencyFormat"; |
| 235 static const UChar fgTripleCurrencySign[] = {0xA4, 0xA4, 0xA4, 0}; |
| 236 |
| 237 inline int32_t _min(int32_t a, int32_t b) { return (a<b) ? a : b; } |
| 238 inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; } |
| 239 |
| 240 //------------------------------------------------------------------------------ |
| 241 // Constructs a DecimalFormat instance in the default locale. |
| 242 |
| 243 DecimalFormat::DecimalFormat(UErrorCode& status) { |
| 244 init(); |
| 245 UParseError parseError; |
| 246 construct(status, parseError); |
| 247 } |
| 248 |
| 249 //------------------------------------------------------------------------------ |
| 250 // Constructs a DecimalFormat instance with the specified number format |
| 251 // pattern in the default locale. |
| 252 |
| 253 DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| 254 UErrorCode& status) { |
| 255 init(); |
| 256 UParseError parseError; |
| 257 construct(status, parseError, &pattern); |
| 258 } |
| 259 |
| 260 //------------------------------------------------------------------------------ |
| 261 // Constructs a DecimalFormat instance with the specified number format |
| 262 // pattern and the number format symbols in the default locale. The |
| 263 // created instance owns the symbols. |
| 264 |
| 265 DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| 266 DecimalFormatSymbols* symbolsToAdopt, |
| 267 UErrorCode& status) { |
| 268 init(); |
| 269 UParseError parseError; |
| 270 if (symbolsToAdopt == NULL) |
| 271 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 272 construct(status, parseError, &pattern, symbolsToAdopt); |
| 273 } |
| 274 |
| 275 DecimalFormat::DecimalFormat( const UnicodeString& pattern, |
| 276 DecimalFormatSymbols* symbolsToAdopt, |
| 277 UParseError& parseErr, |
| 278 UErrorCode& status) { |
| 279 init(); |
| 280 if (symbolsToAdopt == NULL) |
| 281 status = U_ILLEGAL_ARGUMENT_ERROR; |
| 282 construct(status,parseErr, &pattern, symbolsToAdopt); |
| 283 } |
| 284 |
| 285 //------------------------------------------------------------------------------ |
| 286 // Constructs a DecimalFormat instance with the specified number format |
| 287 // pattern and the number format symbols in the default locale. The |
| 288 // created instance owns the clone of the symbols. |
| 289 |
| 290 DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| 291 const DecimalFormatSymbols& symbols, |
| 292 UErrorCode& status) { |
| 293 init(); |
| 294 UParseError parseError; |
| 295 construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols)); |
| 296 } |
| 297 |
| 298 //------------------------------------------------------------------------------ |
| 299 // Constructs a DecimalFormat instance with the specified number format |
| 300 // pattern, the number format symbols, and the number format style. |
| 301 // The created instance owns the clone of the symbols. |
| 302 |
| 303 DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| 304 DecimalFormatSymbols* symbolsToAdopt, |
| 305 NumberFormat::EStyles style, |
| 306 UErrorCode& status) { |
| 307 init(); |
| 308 fStyle = style; |
| 309 UParseError parseError; |
| 310 construct(status, parseError, &pattern, symbolsToAdopt); |
| 311 } |
| 312 |
| 313 //----------------------------------------------------------------------------- |
| 314 // Common DecimalFormat initialization. |
| 315 // Put all fields of an uninitialized object into a known state. |
| 316 // Common code, shared by all constructors. |
| 317 void |
| 318 DecimalFormat::init() { |
| 319 fPosPrefixPattern = 0; |
| 320 fPosSuffixPattern = 0; |
| 321 fNegPrefixPattern = 0; |
| 322 fNegSuffixPattern = 0; |
| 323 fCurrencyChoice = 0; |
| 324 fMultiplier = NULL; |
| 325 fGroupingSize = 0; |
| 326 fGroupingSize2 = 0; |
| 327 fDecimalSeparatorAlwaysShown = FALSE; |
| 328 fSymbols = NULL; |
| 329 fUseSignificantDigits = FALSE; |
| 330 fMinSignificantDigits = 1; |
| 331 fMaxSignificantDigits = 6; |
| 332 fUseExponentialNotation = FALSE; |
| 333 fMinExponentDigits = 0; |
| 334 fExponentSignAlwaysShown = FALSE; |
| 335 fRoundingIncrement = 0; |
| 336 fRoundingMode = kRoundHalfEven; |
| 337 fPad = 0; |
| 338 fFormatWidth = 0; |
| 339 fPadPosition = kPadBeforePrefix; |
| 340 fStyle = NumberFormat::kNumberStyle; |
| 341 fCurrencySignCount = 0; |
| 342 fAffixPatternsForCurrency = NULL; |
| 343 fAffixesForCurrency = NULL; |
| 344 fPluralAffixesForCurrency = NULL; |
| 345 fCurrencyPluralInfo = NULL; |
| 346 } |
| 347 |
| 348 //------------------------------------------------------------------------------ |
| 349 // Constructs a DecimalFormat instance with the specified number format |
| 350 // pattern and the number format symbols in the desired locale. The |
| 351 // created instance owns the symbols. |
| 352 |
| 353 void |
| 354 DecimalFormat::construct(UErrorCode& status, |
| 355 UParseError& parseErr, |
| 356 const UnicodeString* pattern, |
| 357 DecimalFormatSymbols* symbolsToAdopt) |
| 358 { |
| 359 fSymbols = symbolsToAdopt; // Do this BEFORE aborting on status failure!!! |
| 360 fRoundingIncrement = NULL; |
| 361 fRoundingMode = kRoundHalfEven; |
| 362 fPad = kPatternPadEscape; |
| 363 fPadPosition = kPadBeforePrefix; |
| 364 if (U_FAILURE(status)) |
| 365 return; |
| 366 |
| 367 fPosPrefixPattern = fPosSuffixPattern = NULL; |
| 368 fNegPrefixPattern = fNegSuffixPattern = NULL; |
| 369 setMultiplier(1); |
| 370 fGroupingSize = 3; |
| 371 fGroupingSize2 = 0; |
| 372 fDecimalSeparatorAlwaysShown = FALSE; |
| 373 fUseExponentialNotation = FALSE; |
| 374 fMinExponentDigits = 0; |
| 375 |
| 376 if (fSymbols == NULL) |
| 377 { |
| 378 fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status); |
| 379 /* test for NULL */ |
| 380 if (fSymbols == 0) { |
| 381 status = U_MEMORY_ALLOCATION_ERROR; |
| 382 return; |
| 383 } |
| 384 } |
| 385 |
| 386 UnicodeString str; |
| 387 // Uses the default locale's number format pattern if there isn't |
| 388 // one specified. |
| 389 if (pattern == NULL) |
| 390 { |
| 391 int32_t len = 0; |
| 392 UResourceBundle *resource = ures_open(NULL, Locale::getDefault().getName
(), &status); |
| 393 |
| 394 resource = ures_getByKey(resource, fgNumberElements, resource, &status); |
| 395 // TODO : Get the pattern based on the active numbering system for the l
ocale. Right now assumes "latn". |
| 396 resource = ures_getByKey(resource, fgLatn, resource, &status); |
| 397 resource = ures_getByKey(resource, fgPatterns, resource, &status); |
| 398 const UChar *resStr = ures_getStringByKey(resource, fgDecimalFormat, &le
n, &status); |
| 399 str.setTo(TRUE, resStr, len); |
| 400 pattern = &str; |
| 401 ures_close(resource); |
| 402 } |
| 403 |
| 404 if (U_FAILURE(status)) |
| 405 { |
| 406 return; |
| 407 } |
| 408 |
| 409 if (pattern->indexOf((UChar)kCurrencySign) >= 0) { |
| 410 // If it looks like we are going to use a currency pattern |
| 411 // then do the time consuming lookup. |
| 412 setCurrencyForSymbols(); |
| 413 } else { |
| 414 setCurrencyInternally(NULL, status); |
| 415 } |
| 416 |
| 417 const UnicodeString* patternUsed; |
| 418 UnicodeString currencyPluralPatternForOther; |
| 419 // apply pattern |
| 420 if (fStyle == NumberFormat::kPluralCurrencyStyle) { |
| 421 fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), stat
us); |
| 422 if (U_FAILURE(status)) { |
| 423 return; |
| 424 } |
| 425 |
| 426 // the pattern used in format is not fixed until formatting, |
| 427 // in which, the number is known and |
| 428 // will be used to pick the right pattern based on plural count. |
| 429 // Here, set the pattern as the pattern of plural count == "other". |
| 430 // For most locale, the patterns are probably the same for all |
| 431 // plural count. If not, the right pattern need to be re-applied |
| 432 // during format. |
| 433 fCurrencyPluralInfo->getCurrencyPluralPattern("other", currencyPluralPat
ternForOther); |
| 434 patternUsed = ¤cyPluralPatternForOther; |
| 435 // TODO: not needed? |
| 436 setCurrencyForSymbols(); |
| 437 |
| 438 } else { |
| 439 patternUsed = pattern; |
| 440 } |
| 441 |
| 442 if (patternUsed->indexOf(kCurrencySign) != -1) { |
| 443 // initialize for currency, not only for plural format, |
| 444 // but also for mix parsing |
| 445 if (fCurrencyPluralInfo == NULL) { |
| 446 fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(), s
tatus); |
| 447 if (U_FAILURE(status)) { |
| 448 return; |
| 449 } |
| 450 } |
| 451 // need it for mix parsing |
| 452 setupCurrencyAffixPatterns(status); |
| 453 // expanded affixes for plural names |
| 454 if (patternUsed->indexOf(fgTripleCurrencySign) != -1) { |
| 455 setupCurrencyAffixes(*patternUsed, TRUE, TRUE, status); |
| 456 } |
| 457 } |
| 458 |
| 459 applyPatternWithoutExpandAffix(*patternUsed,FALSE, parseErr, status); |
| 460 |
| 461 // expand affixes |
| 462 if (fCurrencySignCount != fgCurrencySignCountInPluralFormat) { |
| 463 expandAffixAdjustWidth(NULL); |
| 464 } |
| 465 |
| 466 // If it was a currency format, apply the appropriate rounding by |
| 467 // resetting the currency. NOTE: this copies fCurrency on top of itself. |
| 468 if (fCurrencySignCount > fgCurrencySignCountZero) { |
| 469 setCurrencyInternally(getCurrency(), status); |
| 470 } |
| 471 } |
| 472 |
| 473 |
| 474 void |
| 475 DecimalFormat::setupCurrencyAffixPatterns(UErrorCode& status) { |
| 476 if (U_FAILURE(status)) { |
| 477 return; |
| 478 } |
| 479 UParseError parseErr; |
| 480 fAffixPatternsForCurrency = initHashForAffixPattern(status); |
| 481 if (U_FAILURE(status)) { |
| 482 return; |
| 483 } |
| 484 |
| 485 // Save the default currency patterns of this locale. |
| 486 // Here, chose onlyApplyPatternWithoutExpandAffix without |
| 487 // expanding the affix patterns into affixes. |
| 488 UnicodeString currencyPattern; |
| 489 UErrorCode error = U_ZERO_ERROR; |
| 490 |
| 491 UResourceBundle *resource = ures_open(NULL, fSymbols->getLocale().getName(),
&error); |
| 492 resource = ures_getByKey(resource, fgNumberElements, resource, &error); |
| 493 // TODO : Get the pattern based on the active numbering system for the local
e. Right now assumes "latn". |
| 494 resource = ures_getByKey(resource, fgLatn, resource, &error); |
| 495 resource = ures_getByKey(resource, fgPatterns, resource, &error); |
| 496 int32_t patLen = 0; |
| 497 const UChar *patResStr = ures_getStringByKey(resource, fgCurrencyFormat, &p
atLen, &error); |
| 498 ures_close(resource); |
| 499 |
| 500 if (U_SUCCESS(error)) { |
| 501 applyPatternWithoutExpandAffix(UnicodeString(patResStr, patLen), false, |
| 502 parseErr, status); |
| 503 AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( |
| 504 *fNegPrefixPattern, |
| 505 *fNegSuffixPattern, |
| 506 *fPosPrefixPattern, |
| 507 *fPosSuffixPattern, |
| 508 UCURR_SYMBOL_NAME); |
| 509 fAffixPatternsForCurrency->put("default", affixPtn, status); |
| 510 } |
| 511 |
| 512 // save the unique currency plural patterns of this locale. |
| 513 Hashtable* pluralPtn = fCurrencyPluralInfo->fPluralCountToCurrencyUnitPatter
n; |
| 514 const UHashElement* element = NULL; |
| 515 int32_t pos = -1; |
| 516 Hashtable pluralPatternSet; |
| 517 while ((element = pluralPtn->nextElement(pos)) != NULL) { |
| 518 const UHashTok valueTok = element->value; |
| 519 const UnicodeString* value = (UnicodeString*)valueTok.pointer; |
| 520 const UHashTok keyTok = element->key; |
| 521 const UnicodeString* key = (UnicodeString*)keyTok.pointer; |
| 522 if (pluralPatternSet.geti(*value) != 1) { |
| 523 pluralPatternSet.puti(*value, 1, status); |
| 524 applyPatternWithoutExpandAffix(*value, false, parseErr, status); |
| 525 AffixPatternsForCurrency* affixPtn = new AffixPatternsForCurrency( |
| 526 *fNegPrefixPattern, |
| 527 *fNegSuffixPattern, |
| 528 *fPosPrefixPattern, |
| 529 *fPosSuffixPattern, |
| 530 UCURR_LONG_NAME); |
| 531 fAffixPatternsForCurrency->put(*key, affixPtn, status); |
| 532 } |
| 533 } |
| 534 } |
| 535 |
| 536 |
| 537 void |
| 538 DecimalFormat::setupCurrencyAffixes(const UnicodeString& pattern, |
| 539 UBool setupForCurrentPattern, |
| 540 UBool setupForPluralPattern, |
| 541 UErrorCode& status) { |
| 542 if (U_FAILURE(status)) { |
| 543 return; |
| 544 } |
| 545 UParseError parseErr; |
| 546 if (setupForCurrentPattern) { |
| 547 if (fAffixesForCurrency) { |
| 548 deleteHashForAffix(fAffixesForCurrency); |
| 549 } |
| 550 fAffixesForCurrency = initHashForAffix(status); |
| 551 if (U_SUCCESS(status)) { |
| 552 applyPatternWithoutExpandAffix(pattern, false, parseErr, status); |
| 553 const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules
(); |
| 554 StringEnumeration* keywords = pluralRules->getKeywords(status); |
| 555 if (U_SUCCESS(status)) { |
| 556 const char* pluralCountCh; |
| 557 while ((pluralCountCh = keywords->next(NULL, status)) != NULL) { |
| 558 if ( U_SUCCESS(status) ) { |
| 559 UnicodeString pluralCount = UnicodeString(pluralCountCh)
; |
| 560 expandAffixAdjustWidth(&pluralCount); |
| 561 AffixesForCurrency* affix = new AffixesForCurrency( |
| 562 fNegativePrefix, fNegativeSuffix, fPositivePrefix, f
PositiveSuffix); |
| 563 fAffixesForCurrency->put(pluralCount, affix, status); |
| 564 } |
| 565 } |
| 566 } |
| 567 delete keywords; |
| 568 } |
| 569 } |
| 570 |
| 571 if (U_FAILURE(status)) { |
| 572 return; |
| 573 } |
| 574 |
| 575 if (setupForPluralPattern) { |
| 576 if (fPluralAffixesForCurrency) { |
| 577 deleteHashForAffix(fPluralAffixesForCurrency); |
| 578 } |
| 579 fPluralAffixesForCurrency = initHashForAffix(status); |
| 580 if (U_SUCCESS(status)) { |
| 581 const PluralRules* pluralRules = fCurrencyPluralInfo->getPluralRules
(); |
| 582 StringEnumeration* keywords = pluralRules->getKeywords(status); |
| 583 if (U_SUCCESS(status)) { |
| 584 const char* pluralCountCh; |
| 585 while ((pluralCountCh = keywords->next(NULL, status)) != NULL) { |
| 586 if ( U_SUCCESS(status) ) { |
| 587 UnicodeString pluralCount = UnicodeString(pluralCountCh)
; |
| 588 UnicodeString ptn; |
| 589 fCurrencyPluralInfo->getCurrencyPluralPattern(pluralCoun
t, ptn); |
| 590 applyPatternInternally(pluralCount, ptn, false, parseErr
, status); |
| 591 AffixesForCurrency* affix = new AffixesForCurrency( |
| 592 fNegativePrefix, fNegativeSuffix, fPositivePrefix, f
PositiveSuffix); |
| 593 fPluralAffixesForCurrency->put(pluralCount, affix, statu
s); |
| 594 } |
| 595 } |
| 596 } |
| 597 delete keywords; |
| 598 } |
| 599 } |
| 600 } |
| 601 |
| 602 |
| 603 //------------------------------------------------------------------------------ |
| 604 |
| 605 DecimalFormat::~DecimalFormat() |
| 606 { |
| 607 delete fPosPrefixPattern; |
| 608 delete fPosSuffixPattern; |
| 609 delete fNegPrefixPattern; |
| 610 delete fNegSuffixPattern; |
| 611 delete fCurrencyChoice; |
| 612 delete fMultiplier; |
| 613 delete fSymbols; |
| 614 delete fRoundingIncrement; |
| 615 deleteHashForAffixPattern(); |
| 616 deleteHashForAffix(fAffixesForCurrency); |
| 617 deleteHashForAffix(fPluralAffixesForCurrency); |
| 618 delete fCurrencyPluralInfo; |
| 619 } |
| 620 |
| 621 //------------------------------------------------------------------------------ |
| 622 // copy constructor |
| 623 |
| 624 DecimalFormat::DecimalFormat(const DecimalFormat &source) : |
| 625 NumberFormat(source) { |
| 626 init(); |
| 627 *this = source; |
| 628 } |
| 629 |
| 630 //------------------------------------------------------------------------------ |
| 631 // assignment operator |
| 632 |
| 633 static void _copy_us_ptr(UnicodeString** pdest, const UnicodeString* source) { |
| 634 if (source == NULL) { |
| 635 delete *pdest; |
| 636 *pdest = NULL; |
| 637 } else if (*pdest == NULL) { |
| 638 *pdest = new UnicodeString(*source); |
| 639 } else { |
| 640 **pdest = *source; |
| 641 } |
| 642 } |
| 643 |
| 644 DecimalFormat& |
| 645 DecimalFormat::operator=(const DecimalFormat& rhs) |
| 646 { |
| 647 if(this != &rhs) { |
| 648 NumberFormat::operator=(rhs); |
| 649 fPositivePrefix = rhs.fPositivePrefix; |
| 650 fPositiveSuffix = rhs.fPositiveSuffix; |
| 651 fNegativePrefix = rhs.fNegativePrefix; |
| 652 fNegativeSuffix = rhs.fNegativeSuffix; |
| 653 _copy_us_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern); |
| 654 _copy_us_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern); |
| 655 _copy_us_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern); |
| 656 _copy_us_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern); |
| 657 if (rhs.fCurrencyChoice == 0) { |
| 658 delete fCurrencyChoice; |
| 659 fCurrencyChoice = 0; |
| 660 } else { |
| 661 fCurrencyChoice = (ChoiceFormat*) rhs.fCurrencyChoice->clone(); |
| 662 } |
| 663 setRoundingIncrement(rhs.getRoundingIncrement()); |
| 664 fRoundingMode = rhs.fRoundingMode; |
| 665 setMultiplier(rhs.getMultiplier()); |
| 666 fGroupingSize = rhs.fGroupingSize; |
| 667 fGroupingSize2 = rhs.fGroupingSize2; |
| 668 fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown; |
| 669 if(fSymbols == NULL) { |
| 670 fSymbols = new DecimalFormatSymbols(*rhs.fSymbols); |
| 671 } else { |
| 672 *fSymbols = *rhs.fSymbols; |
| 673 } |
| 674 fUseExponentialNotation = rhs.fUseExponentialNotation; |
| 675 fExponentSignAlwaysShown = rhs.fExponentSignAlwaysShown; |
| 676 /*Bertrand A. D. Update 98.03.17*/ |
| 677 fCurrencySignCount = rhs.fCurrencySignCount; |
| 678 /*end of Update*/ |
| 679 fMinExponentDigits = rhs.fMinExponentDigits; |
| 680 |
| 681 /* sfb 990629 */ |
| 682 fFormatWidth = rhs.fFormatWidth; |
| 683 fPad = rhs.fPad; |
| 684 fPadPosition = rhs.fPadPosition; |
| 685 /* end sfb */ |
| 686 fMinSignificantDigits = rhs.fMinSignificantDigits; |
| 687 fMaxSignificantDigits = rhs.fMaxSignificantDigits; |
| 688 fUseSignificantDigits = rhs.fUseSignificantDigits; |
| 689 fFormatPattern = rhs.fFormatPattern; |
| 690 fStyle = rhs.fStyle; |
| 691 fCurrencySignCount = rhs.fCurrencySignCount; |
| 692 if (rhs.fCurrencyPluralInfo) { |
| 693 delete fCurrencyPluralInfo; |
| 694 fCurrencyPluralInfo = rhs.fCurrencyPluralInfo->clone(); |
| 695 } |
| 696 if (rhs.fAffixPatternsForCurrency) { |
| 697 UErrorCode status = U_ZERO_ERROR; |
| 698 deleteHashForAffixPattern(); |
| 699 fAffixPatternsForCurrency = initHashForAffixPattern(status); |
| 700 copyHashForAffixPattern(rhs.fAffixPatternsForCurrency, |
| 701 fAffixPatternsForCurrency, status); |
| 702 } |
| 703 if (rhs.fAffixesForCurrency) { |
| 704 UErrorCode status = U_ZERO_ERROR; |
| 705 deleteHashForAffix(fAffixesForCurrency); |
| 706 fAffixesForCurrency = initHashForAffixPattern(status); |
| 707 copyHashForAffix(rhs.fAffixesForCurrency, fAffixesForCurrency, statu
s); |
| 708 } |
| 709 if (rhs.fPluralAffixesForCurrency) { |
| 710 UErrorCode status = U_ZERO_ERROR; |
| 711 deleteHashForAffix(fPluralAffixesForCurrency); |
| 712 fPluralAffixesForCurrency = initHashForAffixPattern(status); |
| 713 copyHashForAffix(rhs.fPluralAffixesForCurrency, fPluralAffixesForCur
rency, status); |
| 714 } |
| 715 } |
| 716 return *this; |
| 717 } |
| 718 |
| 719 //------------------------------------------------------------------------------ |
| 720 |
| 721 UBool |
| 722 DecimalFormat::operator==(const Format& that) const |
| 723 { |
| 724 if (this == &that) |
| 725 return TRUE; |
| 726 |
| 727 // NumberFormat::operator== guarantees this cast is safe |
| 728 const DecimalFormat* other = (DecimalFormat*)&that; |
| 729 |
| 730 #ifdef FMT_DEBUG |
| 731 // This code makes it easy to determine why two format objects that should |
| 732 // be equal aren't. |
| 733 UBool first = TRUE; |
| 734 if (!NumberFormat::operator==(that)) { |
| 735 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 736 debug("NumberFormat::!="); |
| 737 } else { |
| 738 if (!((fPosPrefixPattern == other->fPosPrefixPattern && // both null |
| 739 fPositivePrefix == other->fPositivePrefix) |
| 740 || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 && |
| 741 *fPosPrefixPattern == *other->fPosPrefixPattern))) { |
| 742 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 743 debug("Pos Prefix !="); |
| 744 } |
| 745 if (!((fPosSuffixPattern == other->fPosSuffixPattern && // both null |
| 746 fPositiveSuffix == other->fPositiveSuffix) |
| 747 || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 && |
| 748 *fPosSuffixPattern == *other->fPosSuffixPattern))) { |
| 749 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 750 debug("Pos Suffix !="); |
| 751 } |
| 752 if (!((fNegPrefixPattern == other->fNegPrefixPattern && // both null |
| 753 fNegativePrefix == other->fNegativePrefix) |
| 754 || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 && |
| 755 *fNegPrefixPattern == *other->fNegPrefixPattern))) { |
| 756 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 757 debug("Neg Prefix "); |
| 758 if (fNegPrefixPattern == NULL) { |
| 759 debug("NULL("); |
| 760 debugout(fNegativePrefix); |
| 761 debug(")"); |
| 762 } else { |
| 763 debugout(*fNegPrefixPattern); |
| 764 } |
| 765 debug(" != "); |
| 766 if (other->fNegPrefixPattern == NULL) { |
| 767 debug("NULL("); |
| 768 debugout(other->fNegativePrefix); |
| 769 debug(")"); |
| 770 } else { |
| 771 debugout(*other->fNegPrefixPattern); |
| 772 } |
| 773 } |
| 774 if (!((fNegSuffixPattern == other->fNegSuffixPattern && // both null |
| 775 fNegativeSuffix == other->fNegativeSuffix) |
| 776 || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 && |
| 777 *fNegSuffixPattern == *other->fNegSuffixPattern))) { |
| 778 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 779 debug("Neg Suffix "); |
| 780 if (fNegSuffixPattern == NULL) { |
| 781 debug("NULL("); |
| 782 debugout(fNegativeSuffix); |
| 783 debug(")"); |
| 784 } else { |
| 785 debugout(*fNegSuffixPattern); |
| 786 } |
| 787 debug(" != "); |
| 788 if (other->fNegSuffixPattern == NULL) { |
| 789 debug("NULL("); |
| 790 debugout(other->fNegativeSuffix); |
| 791 debug(")"); |
| 792 } else { |
| 793 debugout(*other->fNegSuffixPattern); |
| 794 } |
| 795 } |
| 796 if (!((fRoundingIncrement == other->fRoundingIncrement) // both null |
| 797 || (fRoundingIncrement != NULL && |
| 798 other->fRoundingIncrement != NULL && |
| 799 *fRoundingIncrement == *other->fRoundingIncrement))) { |
| 800 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 801 debug("Rounding Increment !="); |
| 802 } |
| 803 if (getMultiplier() != other->getMultiplier()) { |
| 804 if (first) { printf("[ "); first = FALSE; } |
| 805 printf("Multiplier %ld != %ld", getMultiplier(), other->getMultiplier())
; |
| 806 } |
| 807 if (fGroupingSize != other->fGroupingSize) { |
| 808 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 809 printf("Grouping Size %ld != %ld", fGroupingSize, other->fGroupingSize); |
| 810 } |
| 811 if (fGroupingSize2 != other->fGroupingSize2) { |
| 812 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 813 printf("Secondary Grouping Size %ld != %ld", fGroupingSize2, other->fGro
upingSize2); |
| 814 } |
| 815 if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) { |
| 816 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 817 printf("Dec Sep Always %d != %d", fDecimalSeparatorAlwaysShown, other->f
DecimalSeparatorAlwaysShown); |
| 818 } |
| 819 if (fUseExponentialNotation != other->fUseExponentialNotation) { |
| 820 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 821 debug("Use Exp !="); |
| 822 } |
| 823 if (!(!fUseExponentialNotation || |
| 824 fMinExponentDigits != other->fMinExponentDigits)) { |
| 825 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 826 debug("Exp Digits !="); |
| 827 } |
| 828 if (*fSymbols != *(other->fSymbols)) { |
| 829 if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| 830 debug("Symbols !="); |
| 831 } |
| 832 // TODO Add debug stuff for significant digits here |
| 833 if (fUseSignificantDigits != other->fUseSignificantDigits) { |
| 834 debug("fUseSignificantDigits !="); |
| 835 } |
| 836 if (fUseSignificantDigits && |
| 837 fMinSignificantDigits != other->fMinSignificantDigits) { |
| 838 debug("fMinSignificantDigits !="); |
| 839 } |
| 840 if (fUseSignificantDigits && |
| 841 fMaxSignificantDigits != other->fMaxSignificantDigits) { |
| 842 debug("fMaxSignificantDigits !="); |
| 843 } |
| 844 |
| 845 if (!first) { printf(" ]"); } |
| 846 if (fCurrencySignCount != other->fCurrencySignCount) { |
| 847 debug("fCurrencySignCount !="); |
| 848 } |
| 849 if (fCurrencyPluralInfo == other->fCurrencyPluralInfo) { |
| 850 debug("fCurrencyPluralInfo == "); |
| 851 if (fCurrencyPluralInfo == NULL) { |
| 852 debug("fCurrencyPluralInfo == NULL"); |
| 853 } |
| 854 } |
| 855 if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL && |
| 856 *fCurrencyPluralInfo != *(other->fCurrencyPluralInfo)) { |
| 857 debug("fCurrencyPluralInfo !="); |
| 858 } |
| 859 if (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo == NULL || |
| 860 fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo != NULL) { |
| 861 debug("fCurrencyPluralInfo one NULL, the other not"); |
| 862 } |
| 863 if (fCurrencyPluralInfo == NULL && other->fCurrencyPluralInfo == NULL) { |
| 864 debug("fCurrencyPluralInfo == "); |
| 865 } |
| 866 } |
| 867 #endif |
| 868 |
| 869 return (NumberFormat::operator==(that) && |
| 870 ((fCurrencySignCount == fgCurrencySignCountInPluralFormat) ? |
| 871 (fAffixPatternsForCurrency->equals(*other->fAffixPatternsForCurrency
)) : |
| 872 (((fPosPrefixPattern == other->fPosPrefixPattern && // both null |
| 873 fPositivePrefix == other->fPositivePrefix) |
| 874 || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 && |
| 875 *fPosPrefixPattern == *other->fPosPrefixPattern)) && |
| 876 ((fPosSuffixPattern == other->fPosSuffixPattern && // both null |
| 877 fPositiveSuffix == other->fPositiveSuffix) |
| 878 || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 && |
| 879 *fPosSuffixPattern == *other->fPosSuffixPattern)) && |
| 880 ((fNegPrefixPattern == other->fNegPrefixPattern && // both null |
| 881 fNegativePrefix == other->fNegativePrefix) |
| 882 || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 && |
| 883 *fNegPrefixPattern == *other->fNegPrefixPattern)) && |
| 884 ((fNegSuffixPattern == other->fNegSuffixPattern && // both null |
| 885 fNegativeSuffix == other->fNegativeSuffix) |
| 886 || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 && |
| 887 *fNegSuffixPattern == *other->fNegSuffixPattern)))) && |
| 888 ((fRoundingIncrement == other->fRoundingIncrement) // both null |
| 889 || (fRoundingIncrement != NULL && |
| 890 other->fRoundingIncrement != NULL && |
| 891 *fRoundingIncrement == *other->fRoundingIncrement)) && |
| 892 getMultiplier() == other->getMultiplier() && |
| 893 fGroupingSize == other->fGroupingSize && |
| 894 fGroupingSize2 == other->fGroupingSize2 && |
| 895 fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown && |
| 896 fUseExponentialNotation == other->fUseExponentialNotation && |
| 897 (!fUseExponentialNotation || |
| 898 fMinExponentDigits == other->fMinExponentDigits) && |
| 899 *fSymbols == *(other->fSymbols) && |
| 900 fUseSignificantDigits == other->fUseSignificantDigits && |
| 901 (!fUseSignificantDigits || |
| 902 (fMinSignificantDigits == other->fMinSignificantDigits && |
| 903 fMaxSignificantDigits == other->fMaxSignificantDigits)) && |
| 904 fCurrencySignCount == other->fCurrencySignCount && |
| 905 ((fCurrencyPluralInfo == other->fCurrencyPluralInfo && |
| 906 fCurrencyPluralInfo == NULL) || |
| 907 (fCurrencyPluralInfo != NULL && other->fCurrencyPluralInfo != NULL && |
| 908 *fCurrencyPluralInfo == *(other->fCurrencyPluralInfo)))); |
| 909 } |
| 910 |
| 911 //------------------------------------------------------------------------------ |
| 912 |
| 913 Format* |
| 914 DecimalFormat::clone() const |
| 915 { |
| 916 return new DecimalFormat(*this); |
| 917 } |
| 918 |
| 919 //------------------------------------------------------------------------------ |
| 920 |
| 921 UnicodeString& |
| 922 DecimalFormat::format(int32_t number, |
| 923 UnicodeString& appendTo, |
| 924 FieldPosition& fieldPosition) const |
| 925 { |
| 926 return format((int64_t)number, appendTo, fieldPosition); |
| 927 } |
| 928 |
| 929 UnicodeString& |
| 930 DecimalFormat::format(int32_t number, |
| 931 UnicodeString& appendTo, |
| 932 FieldPositionIterator* posIter, |
| 933 UErrorCode& status) const |
| 934 { |
| 935 return format((int64_t)number, appendTo, posIter, status); |
| 936 } |
| 937 |
| 938 //------------------------------------------------------------------------------ |
| 939 |
| 940 UnicodeString& |
| 941 DecimalFormat::format(int64_t number, |
| 942 UnicodeString& appendTo, |
| 943 FieldPosition& fieldPosition) const |
| 944 { |
| 945 FieldPositionOnlyHandler handler(fieldPosition); |
| 946 return _format(number, appendTo, handler); |
| 947 } |
| 948 |
| 949 UnicodeString& |
| 950 DecimalFormat::format(int64_t number, |
| 951 UnicodeString& appendTo, |
| 952 FieldPositionIterator* posIter, |
| 953 UErrorCode& status) const |
| 954 { |
| 955 FieldPositionIteratorHandler handler(posIter, status); |
| 956 return _format(number, appendTo, handler); |
| 957 } |
| 958 |
| 959 UnicodeString& |
| 960 DecimalFormat::_format(int64_t number, |
| 961 UnicodeString& appendTo, |
| 962 FieldPositionHandler& handler) const |
| 963 { |
| 964 UErrorCode status = U_ZERO_ERROR; |
| 965 DigitList digits; |
| 966 digits.set(number); |
| 967 return _format(digits, appendTo, handler, status); |
| 968 } |
| 969 |
| 970 //------------------------------------------------------------------------------ |
| 971 |
| 972 UnicodeString& |
| 973 DecimalFormat::format( double number, |
| 974 UnicodeString& appendTo, |
| 975 FieldPosition& fieldPosition) const |
| 976 { |
| 977 FieldPositionOnlyHandler handler(fieldPosition); |
| 978 return _format(number, appendTo, handler); |
| 979 } |
| 980 |
| 981 UnicodeString& |
| 982 DecimalFormat::format( double number, |
| 983 UnicodeString& appendTo, |
| 984 FieldPositionIterator* posIter, |
| 985 UErrorCode& status) const |
| 986 { |
| 987 FieldPositionIteratorHandler handler(posIter, status); |
| 988 return _format(number, appendTo, handler); |
| 989 } |
| 990 |
| 991 UnicodeString& |
| 992 DecimalFormat::_format( double number, |
| 993 UnicodeString& appendTo, |
| 994 FieldPositionHandler& handler) const |
| 995 { |
| 996 // Special case for NaN, sets the begin and end index to be the |
| 997 // the string length of localized name of NaN. |
| 998 // TODO: let NaNs go through DigitList. |
| 999 if (uprv_isNaN(number)) |
| 1000 { |
| 1001 int begin = appendTo.length(); |
| 1002 appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol); |
| 1003 |
| 1004 handler.addAttribute(kIntegerField, begin, appendTo.length()); |
| 1005 |
| 1006 addPadding(appendTo, handler, 0, 0); |
| 1007 return appendTo; |
| 1008 } |
| 1009 |
| 1010 UErrorCode status = U_ZERO_ERROR; |
| 1011 DigitList digits; |
| 1012 digits.set(number); |
| 1013 _format(digits, appendTo, handler, status); |
| 1014 // No way to return status from here. |
| 1015 return appendTo; |
| 1016 } |
| 1017 |
| 1018 //------------------------------------------------------------------------------ |
| 1019 |
| 1020 |
| 1021 UnicodeString& |
| 1022 DecimalFormat::format(const StringPiece &number, |
| 1023 UnicodeString &toAppendTo, |
| 1024 FieldPositionIterator *posIter, |
| 1025 UErrorCode &status) const |
| 1026 { |
| 1027 DigitList dnum; |
| 1028 dnum.set(number, status); |
| 1029 if (U_FAILURE(status)) { |
| 1030 return toAppendTo; |
| 1031 } |
| 1032 FieldPositionIteratorHandler handler(posIter, status); |
| 1033 _format(dnum, toAppendTo, handler, status); |
| 1034 return toAppendTo; |
| 1035 } |
| 1036 |
| 1037 |
| 1038 UnicodeString& |
| 1039 DecimalFormat::format(const DigitList &number, |
| 1040 UnicodeString &appendTo, |
| 1041 FieldPositionIterator *posIter, |
| 1042 UErrorCode &status) const { |
| 1043 FieldPositionIteratorHandler handler(posIter, status); |
| 1044 _format(number, appendTo, handler, status); |
| 1045 return appendTo; |
| 1046 } |
| 1047 |
| 1048 |
| 1049 |
| 1050 UnicodeString& |
| 1051 DecimalFormat::format(const DigitList &number, |
| 1052 UnicodeString& appendTo, |
| 1053 FieldPosition& pos, |
| 1054 UErrorCode &status) const { |
| 1055 FieldPositionOnlyHandler handler(pos); |
| 1056 _format(number, appendTo, handler, status); |
| 1057 return appendTo; |
| 1058 } |
| 1059 |
| 1060 |
| 1061 |
| 1062 UnicodeString& |
| 1063 DecimalFormat::_format(const DigitList &number, |
| 1064 UnicodeString& appendTo, |
| 1065 FieldPositionHandler& handler, |
| 1066 UErrorCode &status) const |
| 1067 { |
| 1068 // Special case for NaN, sets the begin and end index to be the |
| 1069 // the string length of localized name of NaN. |
| 1070 if (number.isNaN()) |
| 1071 { |
| 1072 int begin = appendTo.length(); |
| 1073 appendTo += getConstSymbol(DecimalFormatSymbols::kNaNSymbol); |
| 1074 |
| 1075 handler.addAttribute(kIntegerField, begin, appendTo.length()); |
| 1076 |
| 1077 addPadding(appendTo, handler, 0, 0); |
| 1078 return appendTo; |
| 1079 } |
| 1080 |
| 1081 // Do this BEFORE checking to see if value is infinite or negative! Sets the |
| 1082 // begin and end index to be length of the string composed of |
| 1083 // localized name of Infinite and the positive/negative localized |
| 1084 // signs. |
| 1085 |
| 1086 DigitList adjustedNum(number); // Copy, so we do not alter the original. |
| 1087 adjustedNum.setRoundingMode(fRoundingMode); |
| 1088 if (fMultiplier != NULL) { |
| 1089 adjustedNum.mult(*fMultiplier, status); |
| 1090 } |
| 1091 |
| 1092 /* |
| 1093 * Note: sign is important for zero as well as non-zero numbers. |
| 1094 * Proper detection of -0.0 is needed to deal with the |
| 1095 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. |
| 1096 */ |
| 1097 UBool isNegative = !adjustedNum.isPositive(); |
| 1098 |
| 1099 // Apply rounding after multiplier |
| 1100 if (fRoundingIncrement != NULL) { |
| 1101 adjustedNum.div(*fRoundingIncrement, status); |
| 1102 adjustedNum.toIntegralValue(); |
| 1103 adjustedNum.mult(*fRoundingIncrement, status); |
| 1104 adjustedNum.trim(); |
| 1105 } |
| 1106 |
| 1107 // Special case for INFINITE, |
| 1108 if (adjustedNum.isInfinite()) { |
| 1109 int32_t prefixLen = appendAffix(appendTo, adjustedNum.getDouble(), handl
er, isNegative, TRUE); |
| 1110 |
| 1111 int begin = appendTo.length(); |
| 1112 appendTo += getConstSymbol(DecimalFormatSymbols::kInfinitySymbol); |
| 1113 |
| 1114 handler.addAttribute(kIntegerField, begin, appendTo.length()); |
| 1115 |
| 1116 int32_t suffixLen = appendAffix(appendTo, adjustedNum.getDouble(), handl
er, isNegative, FALSE); |
| 1117 |
| 1118 addPadding(appendTo, handler, prefixLen, suffixLen); |
| 1119 return appendTo; |
| 1120 } |
| 1121 |
| 1122 if (fUseExponentialNotation || areSignificantDigitsUsed()) { |
| 1123 int32_t sigDigits = precision(); |
| 1124 if (sigDigits > 0) { |
| 1125 adjustedNum.round(sigDigits); |
| 1126 } |
| 1127 } else { |
| 1128 // Fixed point format. Round to a set number of fraction digits. |
| 1129 int32_t numFractionDigits = precision(); |
| 1130 adjustedNum.roundFixedPoint(numFractionDigits); |
| 1131 } |
| 1132 |
| 1133 return subformat(appendTo, handler, adjustedNum, FALSE); |
| 1134 } |
| 1135 |
| 1136 |
| 1137 UnicodeString& |
| 1138 DecimalFormat::format( const Formattable& obj, |
| 1139 UnicodeString& appendTo, |
| 1140 FieldPosition& fieldPosition, |
| 1141 UErrorCode& status) const |
| 1142 { |
| 1143 return NumberFormat::format(obj, appendTo, fieldPosition, status); |
| 1144 } |
| 1145 |
| 1146 /** |
| 1147 * Return true if a grouping separator belongs at the given |
| 1148 * position, based on whether grouping is in use and the values of |
| 1149 * the primary and secondary grouping interval. |
| 1150 * @param pos the number of integer digits to the right of |
| 1151 * the current position. Zero indicates the position after the |
| 1152 * rightmost integer digit. |
| 1153 * @return true if a grouping character belongs at the current |
| 1154 * position. |
| 1155 */ |
| 1156 UBool DecimalFormat::isGroupingPosition(int32_t pos) const { |
| 1157 UBool result = FALSE; |
| 1158 if (isGroupingUsed() && (pos > 0) && (fGroupingSize > 0)) { |
| 1159 if ((fGroupingSize2 > 0) && (pos > fGroupingSize)) { |
| 1160 result = ((pos - fGroupingSize) % fGroupingSize2) == 0; |
| 1161 } else { |
| 1162 result = pos % fGroupingSize == 0; |
| 1163 } |
| 1164 } |
| 1165 return result; |
| 1166 } |
| 1167 |
| 1168 //------------------------------------------------------------------------------ |
| 1169 |
| 1170 /** |
| 1171 * Complete the formatting of a finite number. On entry, the DigitList must |
| 1172 * be filled in with the correct digits. |
| 1173 */ |
| 1174 UnicodeString& |
| 1175 DecimalFormat::subformat(UnicodeString& appendTo, |
| 1176 FieldPositionHandler& handler, |
| 1177 DigitList& digits, |
| 1178 UBool isInteger) const |
| 1179 { |
| 1180 // char zero = '0'; |
| 1181 // DigitList returns digits as '0' thru '9', so we will need to |
| 1182 // always need to subtract the character 0 to get the numeric value to use f
or indexing. |
| 1183 |
| 1184 UChar32 localizedDigits[10]; |
| 1185 localizedDigits[0] = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).
char32At(0); |
| 1186 localizedDigits[1] = getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).c
har32At(0); |
| 1187 localizedDigits[2] = getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).c
har32At(0); |
| 1188 localizedDigits[3] = getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol)
.char32At(0); |
| 1189 localizedDigits[4] = getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).
char32At(0); |
| 1190 localizedDigits[5] = getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).
char32At(0); |
| 1191 localizedDigits[6] = getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).c
har32At(0); |
| 1192 localizedDigits[7] = getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol)
.char32At(0); |
| 1193 localizedDigits[8] = getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol)
.char32At(0); |
| 1194 localizedDigits[9] = getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).
char32At(0); |
| 1195 |
| 1196 const UnicodeString *grouping ; |
| 1197 if(fCurrencySignCount > fgCurrencySignCountZero) { |
| 1198 grouping = &getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSepara
torSymbol); |
| 1199 }else{ |
| 1200 grouping = &getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbo
l); |
| 1201 } |
| 1202 const UnicodeString *decimal; |
| 1203 if(fCurrencySignCount > fgCurrencySignCountZero) { |
| 1204 decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol
); |
| 1205 } else { |
| 1206 decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol)
; |
| 1207 } |
| 1208 UBool useSigDig = areSignificantDigitsUsed(); |
| 1209 int32_t maxIntDig = getMaximumIntegerDigits(); |
| 1210 int32_t minIntDig = getMinimumIntegerDigits(); |
| 1211 |
| 1212 // Appends the prefix. |
| 1213 double doubleValue = digits.getDouble(); |
| 1214 int32_t prefixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPo
sitive(), TRUE); |
| 1215 |
| 1216 if (fUseExponentialNotation) |
| 1217 { |
| 1218 int currentLength = appendTo.length(); |
| 1219 int intBegin = currentLength; |
| 1220 int intEnd = -1; |
| 1221 int fracBegin = -1; |
| 1222 |
| 1223 int32_t minFracDig = 0; |
| 1224 if (useSigDig) { |
| 1225 maxIntDig = minIntDig = 1; |
| 1226 minFracDig = getMinimumSignificantDigits() - 1; |
| 1227 } else { |
| 1228 minFracDig = getMinimumFractionDigits(); |
| 1229 if (maxIntDig > kMaxScientificIntegerDigits) { |
| 1230 maxIntDig = 1; |
| 1231 if (maxIntDig < minIntDig) { |
| 1232 maxIntDig = minIntDig; |
| 1233 } |
| 1234 } |
| 1235 if (maxIntDig > minIntDig) { |
| 1236 minIntDig = 1; |
| 1237 } |
| 1238 } |
| 1239 |
| 1240 // Minimum integer digits are handled in exponential format by |
| 1241 // adjusting the exponent. For example, 0.01234 with 3 minimum |
| 1242 // integer digits is "123.4E-4". |
| 1243 |
| 1244 // Maximum integer digits are interpreted as indicating the |
| 1245 // repeating range. This is useful for engineering notation, in |
| 1246 // which the exponent is restricted to a multiple of 3. For |
| 1247 // example, 0.01234 with 3 maximum integer digits is "12.34e-3". |
| 1248 // If maximum integer digits are defined and are larger than |
| 1249 // minimum integer digits, then minimum integer digits are |
| 1250 // ignored. |
| 1251 digits.reduce(); // Removes trailing zero digits. |
| 1252 int32_t exponent = digits.getDecimalAt(); |
| 1253 if (maxIntDig > 1 && maxIntDig != minIntDig) { |
| 1254 // A exponent increment is defined; adjust to it. |
| 1255 exponent = (exponent > 0) ? (exponent - 1) / maxIntDig |
| 1256 : (exponent / maxIntDig) - 1; |
| 1257 exponent *= maxIntDig; |
| 1258 } else { |
| 1259 // No exponent increment is defined; use minimum integer digits. |
| 1260 // If none is specified, as in "#E0", generate 1 integer digit. |
| 1261 exponent -= (minIntDig > 0 || minFracDig > 0) |
| 1262 ? minIntDig : 1; |
| 1263 } |
| 1264 |
| 1265 // We now output a minimum number of digits, and more if there |
| 1266 // are more digits, up to the maximum number of digits. We |
| 1267 // place the decimal point after the "integer" digits, which |
| 1268 // are the first (decimalAt - exponent) digits. |
| 1269 int32_t minimumDigits = minIntDig + minFracDig; |
| 1270 // The number of integer digits is handled specially if the number |
| 1271 // is zero, since then there may be no digits. |
| 1272 int32_t integerDigits = digits.isZero() ? minIntDig : |
| 1273 digits.getDecimalAt() - exponent; |
| 1274 int32_t totalDigits = digits.getCount(); |
| 1275 if (minimumDigits > totalDigits) |
| 1276 totalDigits = minimumDigits; |
| 1277 if (integerDigits > totalDigits) |
| 1278 totalDigits = integerDigits; |
| 1279 |
| 1280 // totalDigits records total number of digits needs to be processed |
| 1281 int32_t i; |
| 1282 for (i=0; i<totalDigits; ++i) |
| 1283 { |
| 1284 if (i == integerDigits) |
| 1285 { |
| 1286 intEnd = appendTo.length(); |
| 1287 handler.addAttribute(kIntegerField, intBegin, intEnd); |
| 1288 |
| 1289 appendTo += *decimal; |
| 1290 |
| 1291 fracBegin = appendTo.length(); |
| 1292 handler.addAttribute(kDecimalSeparatorField, fracBegin - 1, frac
Begin); |
| 1293 } |
| 1294 // Restores the digit character or pads the buffer with zeros. |
| 1295 UChar32 c = (UChar32)((i < digits.getCount()) ? |
| 1296 localizedDigits[digits.getDigitValue(i)] : |
| 1297 localizedDigits[0]); |
| 1298 appendTo += c; |
| 1299 } |
| 1300 |
| 1301 currentLength = appendTo.length(); |
| 1302 |
| 1303 if (intEnd < 0) { |
| 1304 handler.addAttribute(kIntegerField, intBegin, currentLength); |
| 1305 } |
| 1306 if (fracBegin > 0) { |
| 1307 handler.addAttribute(kFractionField, fracBegin, currentLength); |
| 1308 } |
| 1309 |
| 1310 // The exponent is output using the pattern-specified minimum |
| 1311 // exponent digits. There is no maximum limit to the exponent |
| 1312 // digits, since truncating the exponent would appendTo in an |
| 1313 // unacceptable inaccuracy. |
| 1314 appendTo += getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); |
| 1315 |
| 1316 handler.addAttribute(kExponentSymbolField, currentLength, appendTo.lengt
h()); |
| 1317 currentLength = appendTo.length(); |
| 1318 |
| 1319 // For zero values, we force the exponent to zero. We |
| 1320 // must do this here, and not earlier, because the value |
| 1321 // is used to determine integer digit count above. |
| 1322 if (digits.isZero()) |
| 1323 exponent = 0; |
| 1324 |
| 1325 if (exponent < 0) { |
| 1326 appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); |
| 1327 handler.addAttribute(kExponentSignField, currentLength, appendTo.len
gth()); |
| 1328 } else if (fExponentSignAlwaysShown) { |
| 1329 appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); |
| 1330 handler.addAttribute(kExponentSignField, currentLength, appendTo.len
gth()); |
| 1331 } |
| 1332 |
| 1333 currentLength = appendTo.length(); |
| 1334 |
| 1335 DigitList expDigits; |
| 1336 expDigits.set(exponent); |
| 1337 { |
| 1338 int expDig = fMinExponentDigits; |
| 1339 if (fUseExponentialNotation && expDig < 1) { |
| 1340 expDig = 1; |
| 1341 } |
| 1342 for (i=expDigits.getDecimalAt(); i<expDig; ++i) |
| 1343 appendTo += (localizedDigits[0]); |
| 1344 } |
| 1345 for (i=0; i<expDigits.getDecimalAt(); ++i) |
| 1346 { |
| 1347 UChar32 c = (UChar32)((i < expDigits.getCount()) ? |
| 1348 localizedDigits[expDigits.getDigitValue(i)] : |
| 1349 localizedDigits[0]); |
| 1350 appendTo += c; |
| 1351 } |
| 1352 |
| 1353 handler.addAttribute(kExponentField, currentLength, appendTo.length()); |
| 1354 } |
| 1355 else // Not using exponential notation |
| 1356 { |
| 1357 int currentLength = appendTo.length(); |
| 1358 int intBegin = currentLength; |
| 1359 |
| 1360 int32_t sigCount = 0; |
| 1361 int32_t minSigDig = getMinimumSignificantDigits(); |
| 1362 int32_t maxSigDig = getMaximumSignificantDigits(); |
| 1363 if (!useSigDig) { |
| 1364 minSigDig = 0; |
| 1365 maxSigDig = INT32_MAX; |
| 1366 } |
| 1367 |
| 1368 // Output the integer portion. Here 'count' is the total |
| 1369 // number of integer digits we will display, including both |
| 1370 // leading zeros required to satisfy getMinimumIntegerDigits, |
| 1371 // and actual digits present in the number. |
| 1372 int32_t count = useSigDig ? |
| 1373 _max(1, digits.getDecimalAt()) : minIntDig; |
| 1374 if (digits.getDecimalAt() > 0 && count < digits.getDecimalAt()) { |
| 1375 count = digits.getDecimalAt(); |
| 1376 } |
| 1377 |
| 1378 // Handle the case where getMaximumIntegerDigits() is smaller |
| 1379 // than the real number of integer digits. If this is so, we |
| 1380 // output the least significant max integer digits. For example, |
| 1381 // the value 1997 printed with 2 max integer digits is just "97". |
| 1382 |
| 1383 int32_t digitIndex = 0; // Index into digitList.fDigits[] |
| 1384 if (count > maxIntDig && maxIntDig >= 0) { |
| 1385 count = maxIntDig; |
| 1386 digitIndex = digits.getDecimalAt() - count; |
| 1387 } |
| 1388 |
| 1389 int32_t sizeBeforeIntegerPart = appendTo.length(); |
| 1390 |
| 1391 int32_t i; |
| 1392 for (i=count-1; i>=0; --i) |
| 1393 { |
| 1394 if (i < digits.getDecimalAt() && digitIndex < digits.getCount() && |
| 1395 sigCount < maxSigDig) { |
| 1396 // Output a real digit |
| 1397 appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitI
ndex++)]; |
| 1398 ++sigCount; |
| 1399 } |
| 1400 else |
| 1401 { |
| 1402 // Output a zero (leading or trailing) |
| 1403 appendTo += localizedDigits[0]; |
| 1404 if (sigCount > 0) { |
| 1405 ++sigCount; |
| 1406 } |
| 1407 } |
| 1408 |
| 1409 // Output grouping separator if necessary. |
| 1410 if (isGroupingPosition(i)) { |
| 1411 currentLength = appendTo.length(); |
| 1412 appendTo.append(*grouping); |
| 1413 handler.addAttribute(kGroupingSeparatorField, currentLength, app
endTo.length()); |
| 1414 } |
| 1415 } |
| 1416 |
| 1417 // TODO(dlf): this looks like it was a bug, we marked the int field as e
nding |
| 1418 // before the zero was generated. |
| 1419 // Record field information for caller. |
| 1420 // if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| 1421 // fieldPosition.setEndIndex(appendTo.length()); |
| 1422 |
| 1423 // Determine whether or not there are any printable fractional |
| 1424 // digits. If we've used up the digits we know there aren't. |
| 1425 UBool fractionPresent = (!isInteger && digitIndex < digits.getCount()) |
| |
| 1426 (useSigDig ? (sigCount < minSigDig) : (getMinimumFractionDigits() >
0)); |
| 1427 |
| 1428 // If there is no fraction present, and we haven't printed any |
| 1429 // integer digits, then print a zero. Otherwise we won't print |
| 1430 // _any_ digits, and we won't be able to parse this string. |
| 1431 if (!fractionPresent && appendTo.length() == sizeBeforeIntegerPart) |
| 1432 appendTo += localizedDigits[0]; |
| 1433 |
| 1434 currentLength = appendTo.length(); |
| 1435 handler.addAttribute(kIntegerField, intBegin, currentLength); |
| 1436 |
| 1437 // Output the decimal separator if we always do so. |
| 1438 if (fDecimalSeparatorAlwaysShown || fractionPresent) { |
| 1439 appendTo += *decimal; |
| 1440 handler.addAttribute(kDecimalSeparatorField, currentLength, appendTo
.length()); |
| 1441 currentLength = appendTo.length(); |
| 1442 } |
| 1443 |
| 1444 int fracBegin = currentLength; |
| 1445 |
| 1446 count = useSigDig ? INT32_MAX : getMaximumFractionDigits(); |
| 1447 if (useSigDig && (sigCount == maxSigDig || |
| 1448 (sigCount >= minSigDig && digitIndex == digits.getCoun
t()))) { |
| 1449 count = 0; |
| 1450 } |
| 1451 |
| 1452 for (i=0; i < count; ++i) { |
| 1453 // Here is where we escape from the loop. We escape |
| 1454 // if we've output the maximum fraction digits |
| 1455 // (specified in the for expression above). We also |
| 1456 // stop when we've output the minimum digits and |
| 1457 // either: we have an integer, so there is no |
| 1458 // fractional stuff to display, or we're out of |
| 1459 // significant digits. |
| 1460 if (!useSigDig && i >= getMinimumFractionDigits() && |
| 1461 (isInteger || digitIndex >= digits.getCount())) { |
| 1462 break; |
| 1463 } |
| 1464 |
| 1465 // Output leading fractional zeros. These are zeros |
| 1466 // that come after the decimal but before any |
| 1467 // significant digits. These are only output if |
| 1468 // abs(number being formatted) < 1.0. |
| 1469 if (-1-i > (digits.getDecimalAt()-1)) { |
| 1470 appendTo += localizedDigits[0]; |
| 1471 continue; |
| 1472 } |
| 1473 |
| 1474 // Output a digit, if we have any precision left, or a |
| 1475 // zero if we don't. We don't want to output noise digits. |
| 1476 if (!isInteger && digitIndex < digits.getCount()) { |
| 1477 appendTo += (UChar32)localizedDigits[digits.getDigitValue(digitI
ndex++)]; |
| 1478 } else { |
| 1479 appendTo += localizedDigits[0]; |
| 1480 } |
| 1481 |
| 1482 // If we reach the maximum number of significant |
| 1483 // digits, or if we output all the real digits and |
| 1484 // reach the minimum, then we are done. |
| 1485 ++sigCount; |
| 1486 if (useSigDig && |
| 1487 (sigCount == maxSigDig || |
| 1488 (digitIndex == digits.getCount() && sigCount >= minSigDig))) { |
| 1489 break; |
| 1490 } |
| 1491 } |
| 1492 |
| 1493 handler.addAttribute(kFractionField, fracBegin, appendTo.length()); |
| 1494 } |
| 1495 |
| 1496 int32_t suffixLen = appendAffix(appendTo, doubleValue, handler, !digits.isPo
sitive(), FALSE); |
| 1497 |
| 1498 addPadding(appendTo, handler, prefixLen, suffixLen); |
| 1499 return appendTo; |
| 1500 } |
| 1501 |
| 1502 /** |
| 1503 * Inserts the character fPad as needed to expand result to fFormatWidth. |
| 1504 * @param result the string to be padded |
| 1505 */ |
| 1506 void DecimalFormat::addPadding(UnicodeString& appendTo, |
| 1507 FieldPositionHandler& handler, |
| 1508 int32_t prefixLen, |
| 1509 int32_t suffixLen) const |
| 1510 { |
| 1511 if (fFormatWidth > 0) { |
| 1512 int32_t len = fFormatWidth - appendTo.length(); |
| 1513 if (len > 0) { |
| 1514 UnicodeString padding; |
| 1515 for (int32_t i=0; i<len; ++i) { |
| 1516 padding += fPad; |
| 1517 } |
| 1518 switch (fPadPosition) { |
| 1519 case kPadAfterPrefix: |
| 1520 appendTo.insert(prefixLen, padding); |
| 1521 break; |
| 1522 case kPadBeforePrefix: |
| 1523 appendTo.insert(0, padding); |
| 1524 break; |
| 1525 case kPadBeforeSuffix: |
| 1526 appendTo.insert(appendTo.length() - suffixLen, padding); |
| 1527 break; |
| 1528 case kPadAfterSuffix: |
| 1529 appendTo += padding; |
| 1530 break; |
| 1531 } |
| 1532 if (fPadPosition == kPadBeforePrefix || fPadPosition == kPadAfterPre
fix) { |
| 1533 handler.shiftLast(len); |
| 1534 } |
| 1535 } |
| 1536 } |
| 1537 } |
| 1538 |
| 1539 //------------------------------------------------------------------------------ |
| 1540 |
| 1541 void |
| 1542 DecimalFormat::parse(const UnicodeString& text, |
| 1543 Formattable& result, |
| 1544 UErrorCode& status) const |
| 1545 { |
| 1546 NumberFormat::parse(text, result, status); |
| 1547 } |
| 1548 |
| 1549 void |
| 1550 DecimalFormat::parse(const UnicodeString& text, |
| 1551 Formattable& result, |
| 1552 ParsePosition& parsePosition) const { |
| 1553 parse(text, result, parsePosition, FALSE); |
| 1554 } |
| 1555 |
| 1556 Formattable& DecimalFormat::parseCurrency(const UnicodeString& text, |
| 1557 Formattable& result, |
| 1558 ParsePosition& pos) const { |
| 1559 parse(text, result, pos, TRUE); |
| 1560 return result; |
| 1561 } |
| 1562 |
| 1563 /** |
| 1564 * Parses the given text as either a number or a currency amount. |
| 1565 * @param text the string to parse |
| 1566 * @param result output parameter for the result |
| 1567 * @param parsePosition input-output position; on input, the |
| 1568 * position within text to match; must have 0 <= pos.getIndex() < |
| 1569 * text.length(); on output, the position after the last matched |
| 1570 * character. If the parse fails, the position in unchanged upon |
| 1571 * output. |
| 1572 * @param parseCurrency if true, a currency amount is parsed; |
| 1573 * otherwise a Number is parsed |
| 1574 */ |
| 1575 void DecimalFormat::parse(const UnicodeString& text, |
| 1576 Formattable& result, |
| 1577 ParsePosition& parsePosition, |
| 1578 UBool parseCurrency) const { |
| 1579 int32_t backup; |
| 1580 int32_t i = backup = parsePosition.getIndex(); |
| 1581 |
| 1582 // clear any old contents in the result. In particular, clears any DigitLis
t |
| 1583 // that it may be holding. |
| 1584 result.setLong(0); |
| 1585 |
| 1586 // Handle NaN as a special case: |
| 1587 |
| 1588 // Skip padding characters, if around prefix |
| 1589 if (fFormatWidth > 0 && (fPadPosition == kPadBeforePrefix || |
| 1590 fPadPosition == kPadAfterPrefix)) { |
| 1591 i = skipPadding(text, i); |
| 1592 } |
| 1593 // If the text is composed of the representation of NaN, returns NaN.length |
| 1594 const UnicodeString *nan = &getConstSymbol(DecimalFormatSymbols::kNaNSymbol)
; |
| 1595 int32_t nanLen = (text.compare(i, nan->length(), *nan) |
| 1596 ? 0 : nan->length()); |
| 1597 if (nanLen) { |
| 1598 i += nanLen; |
| 1599 if (fFormatWidth > 0 && (fPadPosition == kPadBeforeSuffix || |
| 1600 fPadPosition == kPadAfterSuffix)) { |
| 1601 i = skipPadding(text, i); |
| 1602 } |
| 1603 parsePosition.setIndex(i); |
| 1604 result.setDouble(uprv_getNaN()); |
| 1605 return; |
| 1606 } |
| 1607 |
| 1608 // NaN parse failed; start over |
| 1609 i = backup; |
| 1610 |
| 1611 // status is used to record whether a number is infinite. |
| 1612 UBool status[fgStatusLength]; |
| 1613 UChar curbuf[4]; |
| 1614 UChar* currency = parseCurrency ? curbuf : NULL; |
| 1615 DigitList *digits = new DigitList; |
| 1616 if (digits == NULL) { |
| 1617 return; // no way to report error from here. |
| 1618 } |
| 1619 |
| 1620 if (fCurrencySignCount > fgCurrencySignCountZero) { |
| 1621 if (!parseForCurrency(text, parsePosition, *digits, |
| 1622 status, currency)) { |
| 1623 delete digits; |
| 1624 return; |
| 1625 } |
| 1626 } else { |
| 1627 if (!subparse(text, |
| 1628 fNegPrefixPattern, fNegSuffixPattern, |
| 1629 fPosPrefixPattern, fPosSuffixPattern, |
| 1630 FALSE, UCURR_SYMBOL_NAME, |
| 1631 parsePosition, *digits, status, currency)) { |
| 1632 parsePosition.setIndex(backup); |
| 1633 delete digits; |
| 1634 return; |
| 1635 } |
| 1636 } |
| 1637 |
| 1638 // Handle infinity |
| 1639 if (status[fgStatusInfinite]) { |
| 1640 double inf = uprv_getInfinity(); |
| 1641 result.setDouble(digits->isPositive() ? inf : -inf); |
| 1642 delete digits; // TODO: set the dl to infinity, and let it fall into
the code below. |
| 1643 } |
| 1644 |
| 1645 else { |
| 1646 |
| 1647 if (fMultiplier != NULL) { |
| 1648 UErrorCode ec = U_ZERO_ERROR; |
| 1649 digits->div(*fMultiplier, ec); |
| 1650 } |
| 1651 |
| 1652 // Negative zero special case: |
| 1653 // if parsing integerOnly, change to +0, which goes into an int32 in
a Formattable. |
| 1654 // if not parsing integerOnly, leave as -0, which a double can repres
ent. |
| 1655 if (digits->isZero() && !digits->isPositive() && isParseIntegerOnly()) { |
| 1656 digits->setPositive(TRUE); |
| 1657 } |
| 1658 result.adoptDigitList(digits); |
| 1659 } |
| 1660 |
| 1661 if (parseCurrency) { |
| 1662 UErrorCode ec = U_ZERO_ERROR; |
| 1663 Formattable n(result); |
| 1664 result.adoptObject(new CurrencyAmount(n, curbuf, ec)); |
| 1665 U_ASSERT(U_SUCCESS(ec)); // should always succeed |
| 1666 } |
| 1667 } |
| 1668 |
| 1669 |
| 1670 |
| 1671 UBool |
| 1672 DecimalFormat::parseForCurrency(const UnicodeString& text, |
| 1673 ParsePosition& parsePosition, |
| 1674 DigitList& digits, |
| 1675 UBool* status, |
| 1676 UChar* currency) const { |
| 1677 int origPos = parsePosition.getIndex(); |
| 1678 int maxPosIndex = origPos; |
| 1679 int maxErrorPos = -1; |
| 1680 // First, parse against current pattern. |
| 1681 // Since current pattern could be set by applyPattern(), |
| 1682 // it could be an arbitrary pattern, and it may not be the one |
| 1683 // defined in current locale. |
| 1684 UBool tmpStatus[fgStatusLength]; |
| 1685 ParsePosition tmpPos(origPos); |
| 1686 DigitList tmpDigitList; |
| 1687 UBool found; |
| 1688 if (fStyle == NumberFormat::kPluralCurrencyStyle) { |
| 1689 found = subparse(text, |
| 1690 fNegPrefixPattern, fNegSuffixPattern, |
| 1691 fPosPrefixPattern, fPosSuffixPattern, |
| 1692 TRUE, UCURR_LONG_NAME, |
| 1693 tmpPos, tmpDigitList, tmpStatus, currency); |
| 1694 } else { |
| 1695 found = subparse(text, |
| 1696 fNegPrefixPattern, fNegSuffixPattern, |
| 1697 fPosPrefixPattern, fPosSuffixPattern, |
| 1698 TRUE, UCURR_SYMBOL_NAME, |
| 1699 tmpPos, tmpDigitList, tmpStatus, currency); |
| 1700 } |
| 1701 if (found) { |
| 1702 if (tmpPos.getIndex() > maxPosIndex) { |
| 1703 maxPosIndex = tmpPos.getIndex(); |
| 1704 for (int32_t i = 0; i < fgStatusLength; ++i) { |
| 1705 status[i] = tmpStatus[i]; |
| 1706 } |
| 1707 digits = tmpDigitList; |
| 1708 } |
| 1709 } else { |
| 1710 maxErrorPos = tmpPos.getErrorIndex(); |
| 1711 } |
| 1712 // Then, parse against affix patterns. |
| 1713 // Those are currency patterns and currency plural patterns. |
| 1714 int32_t pos = -1; |
| 1715 const UHashElement* element = NULL; |
| 1716 while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { |
| 1717 const UHashTok keyTok = element->key; |
| 1718 const UHashTok valueTok = element->value; |
| 1719 const AffixPatternsForCurrency* affixPtn = (AffixPatternsForCurrency*)va
lueTok.pointer; |
| 1720 UBool tmpStatus[fgStatusLength]; |
| 1721 ParsePosition tmpPos(origPos); |
| 1722 DigitList tmpDigitList; |
| 1723 UBool result = subparse(text, |
| 1724 &affixPtn->negPrefixPatternForCurrency, |
| 1725 &affixPtn->negSuffixPatternForCurrency, |
| 1726 &affixPtn->posPrefixPatternForCurrency, |
| 1727 &affixPtn->posSuffixPatternForCurrency, |
| 1728 TRUE, affixPtn->patternType, |
| 1729 tmpPos, tmpDigitList, tmpStatus, currency); |
| 1730 if (result) { |
| 1731 found = true; |
| 1732 if (tmpPos.getIndex() > maxPosIndex) { |
| 1733 maxPosIndex = tmpPos.getIndex(); |
| 1734 for (int32_t i = 0; i < fgStatusLength; ++i) { |
| 1735 status[i] = tmpStatus[i]; |
| 1736 } |
| 1737 digits = tmpDigitList; |
| 1738 } |
| 1739 } else { |
| 1740 maxErrorPos = (tmpPos.getErrorIndex() > maxErrorPos) ? |
| 1741 tmpPos.getErrorIndex() : maxErrorPos; |
| 1742 } |
| 1743 } |
| 1744 // Finally, parse against simple affix to find the match. |
| 1745 // For example, in TestMonster suite, |
| 1746 // if the to-be-parsed text is "-\u00A40,00". |
| 1747 // complexAffixCompare will not find match, |
| 1748 // since there is no ISO code matches "\u00A4", |
| 1749 // and the parse stops at "\u00A4". |
| 1750 // We will just use simple affix comparison (look for exact match) |
| 1751 // to pass it. |
| 1752 UBool tmpStatus_2[fgStatusLength]; |
| 1753 ParsePosition tmpPos_2(origPos); |
| 1754 DigitList tmpDigitList_2; |
| 1755 // set currencySignCount to 0 so that compareAffix function will |
| 1756 // fall to compareSimpleAffix path, not compareComplexAffix path. |
| 1757 // ?? TODO: is it right? need "false"? |
| 1758 UBool result = subparse(text, |
| 1759 &fNegativePrefix, &fNegativeSuffix, |
| 1760 &fPositivePrefix, &fPositiveSuffix, |
| 1761 FALSE, UCURR_SYMBOL_NAME, |
| 1762 tmpPos_2, tmpDigitList_2, tmpStatus_2, |
| 1763 currency); |
| 1764 if (result) { |
| 1765 if (tmpPos_2.getIndex() > maxPosIndex) { |
| 1766 maxPosIndex = tmpPos_2.getIndex(); |
| 1767 for (int32_t i = 0; i < fgStatusLength; ++i) { |
| 1768 status[i] = tmpStatus_2[i]; |
| 1769 } |
| 1770 digits = tmpDigitList_2; |
| 1771 } |
| 1772 found = true; |
| 1773 } else { |
| 1774 maxErrorPos = (tmpPos_2.getErrorIndex() > maxErrorPos) ? |
| 1775 tmpPos_2.getErrorIndex() : maxErrorPos; |
| 1776 } |
| 1777 |
| 1778 if (!found) { |
| 1779 //parsePosition.setIndex(origPos); |
| 1780 parsePosition.setErrorIndex(maxErrorPos); |
| 1781 } else { |
| 1782 parsePosition.setIndex(maxPosIndex); |
| 1783 parsePosition.setErrorIndex(-1); |
| 1784 } |
| 1785 return found; |
| 1786 } |
| 1787 |
| 1788 |
| 1789 /** |
| 1790 * Parse the given text into a number. The text is parsed beginning at |
| 1791 * parsePosition, until an unparseable character is seen. |
| 1792 * @param text the string to parse. |
| 1793 * @param negPrefix negative prefix. |
| 1794 * @param negSuffix negative suffix. |
| 1795 * @param posPrefix positive prefix. |
| 1796 * @param posSuffix positive suffix. |
| 1797 * @param currencyParsing whether it is currency parsing or not. |
| 1798 * @param type the currency type to parse against, LONG_NAME only or not. |
| 1799 * @param parsePosition The position at which to being parsing. Upon |
| 1800 * return, the first unparsed character. |
| 1801 * @param digits the DigitList to set to the parsed value. |
| 1802 * @param status output param containing boolean status flags indicating |
| 1803 * whether the value was infinite and whether it was positive. |
| 1804 * @param currency return value for parsed currency, for generic |
| 1805 * currency parsing mode, or NULL for normal parsing. In generic |
| 1806 * currency parsing mode, any currency is parsed, not just the |
| 1807 * currency that this formatter is set to. |
| 1808 */ |
| 1809 UBool DecimalFormat::subparse(const UnicodeString& text, |
| 1810 const UnicodeString* negPrefix, |
| 1811 const UnicodeString* negSuffix, |
| 1812 const UnicodeString* posPrefix, |
| 1813 const UnicodeString* posSuffix, |
| 1814 UBool currencyParsing, |
| 1815 int8_t type, |
| 1816 ParsePosition& parsePosition, |
| 1817 DigitList& digits, UBool* status, |
| 1818 UChar* currency) const |
| 1819 { |
| 1820 // The parsing process builds up the number as char string, in the neutral
format that |
| 1821 // will be acceptable to the decNumber library, then at the end passes that
string |
| 1822 // off for conversion to a decNumber. |
| 1823 UErrorCode err = U_ZERO_ERROR; |
| 1824 CharString parsedNum; |
| 1825 digits.setToZero(); |
| 1826 |
| 1827 int32_t position = parsePosition.getIndex(); |
| 1828 int32_t oldStart = position; |
| 1829 |
| 1830 // Match padding before prefix |
| 1831 if (fFormatWidth > 0 && fPadPosition == kPadBeforePrefix) { |
| 1832 position = skipPadding(text, position); |
| 1833 } |
| 1834 |
| 1835 // Match positive and negative prefixes; prefer longest match. |
| 1836 int32_t posMatch = compareAffix(text, position, FALSE, TRUE, posPrefix, curr
encyParsing, type, currency); |
| 1837 int32_t negMatch = compareAffix(text, position, TRUE, TRUE, negPrefix,curren
cyParsing, type, currency); |
| 1838 if (posMatch >= 0 && negMatch >= 0) { |
| 1839 if (posMatch > negMatch) { |
| 1840 negMatch = -1; |
| 1841 } else if (negMatch > posMatch) { |
| 1842 posMatch = -1; |
| 1843 } |
| 1844 } |
| 1845 if (posMatch >= 0) { |
| 1846 position += posMatch; |
| 1847 parsedNum.append('+', err); |
| 1848 } else if (negMatch >= 0) { |
| 1849 position += negMatch; |
| 1850 parsedNum.append('-', err); |
| 1851 } else { |
| 1852 parsePosition.setErrorIndex(position); |
| 1853 return FALSE; |
| 1854 } |
| 1855 |
| 1856 // Match padding before prefix |
| 1857 if (fFormatWidth > 0 && fPadPosition == kPadAfterPrefix) { |
| 1858 position = skipPadding(text, position); |
| 1859 } |
| 1860 |
| 1861 // process digits or Inf, find decimal position |
| 1862 const UnicodeString *inf = &getConstSymbol(DecimalFormatSymbols::kInfinitySy
mbol); |
| 1863 int32_t infLen = (text.compare(position, inf->length(), *inf) |
| 1864 ? 0 : inf->length()); |
| 1865 position += infLen; // infLen is non-zero when it does equal to infinity |
| 1866 status[fgStatusInfinite] = (UBool)infLen; |
| 1867 if (infLen) { |
| 1868 parsedNum.append("Infinity", err); |
| 1869 } else { |
| 1870 // We now have a string of digits, possibly with grouping symbols, |
| 1871 // and decimal points. We want to process these into a DigitList. |
| 1872 // We don't want to put a bunch of leading zeros into the DigitList |
| 1873 // though, so we keep track of the location of the decimal point, |
| 1874 // put only significant digits into the DigitList, and adjust the |
| 1875 // exponent as needed. |
| 1876 |
| 1877 UChar32 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).ch
ar32At(0); |
| 1878 |
| 1879 const UnicodeString *decimal; |
| 1880 if(fCurrencySignCount > fgCurrencySignCountZero) { |
| 1881 decimal = &getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSy
mbol); |
| 1882 } else { |
| 1883 decimal = &getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSym
bol); |
| 1884 } |
| 1885 const UnicodeString *grouping = &getConstSymbol(DecimalFormatSymbols::kG
roupingSeparatorSymbol); |
| 1886 UBool sawDecimal = FALSE; |
| 1887 UBool sawDigit = FALSE; |
| 1888 int32_t backup = -1; |
| 1889 int32_t digit; |
| 1890 int32_t textLength = text.length(); // One less pointer to follow |
| 1891 int32_t groupingLen = grouping->length(); |
| 1892 int32_t decimalLen = decimal->length(); |
| 1893 |
| 1894 // We have to track digitCount ourselves, because digits.fCount will |
| 1895 // pin when the maximum allowable digits is reached. |
| 1896 int32_t digitCount = 0; |
| 1897 |
| 1898 for (; position < textLength; ) |
| 1899 { |
| 1900 UChar32 ch = text.char32At(position); |
| 1901 |
| 1902 /* We recognize all digit ranges, not only the Latin digit range |
| 1903 * '0'..'9'. We do so by using the Character.digit() method, |
| 1904 * which converts a valid Unicode digit to the range 0..9. |
| 1905 * |
| 1906 * The character 'ch' may be a digit. If so, place its value |
| 1907 * from 0 to 9 in 'digit'. First try using the locale digit, |
| 1908 * which may or MAY NOT be a standard Unicode digit range. If |
| 1909 * this fails, try using the standard Unicode digit ranges by |
| 1910 * calling Character.digit(). If this also fails, digit will |
| 1911 * have a value outside the range 0..9. |
| 1912 */ |
| 1913 digit = ch - zero; |
| 1914 if (digit < 0 || digit > 9) |
| 1915 { |
| 1916 digit = u_charDigitValue(ch); |
| 1917 } |
| 1918 |
| 1919 // As a last resort, look through the localized digits if the zero d
igit |
| 1920 // is not a "standard" Unicode digit. |
| 1921 if ( (digit < 0 || digit > 9) && u_charDigitValue(zero) != 0) { |
| 1922 digit = 0; |
| 1923 if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymbol)(
DecimalFormatSymbols::kZeroDigitSymbol)).char32At(0) == ch ) { |
| 1924 break; |
| 1925 } |
| 1926 for (digit = 1 ; digit < 10 ; digit++ ) { |
| 1927 if ( getConstSymbol((DecimalFormatSymbols::ENumberFormatSymb
ol)(DecimalFormatSymbols::kOneDigitSymbol+digit-1)).char32At(0) == ch ) { |
| 1928 break; |
| 1929 } |
| 1930 } |
| 1931 } |
| 1932 |
| 1933 if (digit >= 0 && digit <= 9) |
| 1934 { |
| 1935 // Cancel out backup setting (see grouping handler below) |
| 1936 backup = -1; |
| 1937 |
| 1938 sawDigit = TRUE; |
| 1939 // output a regular non-zero digit. |
| 1940 ++digitCount; |
| 1941 parsedNum.append((char)(digit + '0'), err); |
| 1942 position += U16_LENGTH(ch); |
| 1943 } |
| 1944 else if (groupingLen > 0 && !text.compare(position, groupingLen, *gr
ouping) && isGroupingUsed()) |
| 1945 { |
| 1946 // Ignore grouping characters, if we are using them, but require |
| 1947 // that they be followed by a digit. Otherwise we backup and |
| 1948 // reprocess them. |
| 1949 backup = position; |
| 1950 position += groupingLen; |
| 1951 } |
| 1952 else if (!text.compare(position, decimalLen, *decimal) && !isParseIn
tegerOnly() && !sawDecimal) |
| 1953 { |
| 1954 // If we're only parsing integers, or if we ALREADY saw the |
| 1955 // decimal, then don't parse this one. |
| 1956 |
| 1957 parsedNum.append('.', err); |
| 1958 sawDecimal = TRUE; |
| 1959 position += decimalLen; |
| 1960 } |
| 1961 else { |
| 1962 const UnicodeString *tmp; |
| 1963 tmp = &getConstSymbol(DecimalFormatSymbols::kExponentialSymbol); |
| 1964 if (!text.compare(position, tmp->length(), *tmp)) // error co
de is set below if !sawDigit |
| 1965 { |
| 1966 // Parse sign, if present |
| 1967 int32_t pos = position + tmp->length(); |
| 1968 char exponentSign = '+'; |
| 1969 |
| 1970 if (pos < textLength) |
| 1971 { |
| 1972 tmp = &getConstSymbol(DecimalFormatSymbols::kPlusSignSym
bol); |
| 1973 if (!text.compare(pos, tmp->length(), *tmp)) |
| 1974 { |
| 1975 pos += tmp->length(); |
| 1976 } |
| 1977 else { |
| 1978 tmp = &getConstSymbol(DecimalFormatSymbols::kMinusSi
gnSymbol); |
| 1979 if (!text.compare(pos, tmp->length(), *tmp)) |
| 1980 { |
| 1981 exponentSign = '-'; |
| 1982 pos += tmp->length(); |
| 1983 } |
| 1984 } |
| 1985 } |
| 1986 |
| 1987 UBool sawExponentDigit = FALSE; |
| 1988 while (pos < textLength) { |
| 1989 ch = text[(int32_t)pos]; |
| 1990 digit = ch - zero; |
| 1991 |
| 1992 if (digit < 0 || digit > 9) { |
| 1993 digit = u_charDigitValue(ch); |
| 1994 } |
| 1995 if (0 <= digit && digit <= 9) { |
| 1996 if (!sawExponentDigit) { |
| 1997 parsedNum.append('E', err); |
| 1998 parsedNum.append(exponentSign, err); |
| 1999 sawExponentDigit = TRUE; |
| 2000 } |
| 2001 ++pos; |
| 2002 parsedNum.append((char)(digit + '0'), err); |
| 2003 } else { |
| 2004 break; |
| 2005 } |
| 2006 } |
| 2007 |
| 2008 if (sawExponentDigit) { |
| 2009 position = pos; // Advance past the exponent |
| 2010 } |
| 2011 |
| 2012 break; // Whether we fail or succeed, we exit this loop |
| 2013 } |
| 2014 else { |
| 2015 break; |
| 2016 } |
| 2017 } |
| 2018 } |
| 2019 |
| 2020 if (backup != -1) |
| 2021 { |
| 2022 position = backup; |
| 2023 } |
| 2024 |
| 2025 // If there was no decimal point we have an integer |
| 2026 |
| 2027 // If none of the text string was recognized. For example, parse |
| 2028 // "x" with pattern "#0.00" (return index and error index both 0) |
| 2029 // parse "$" with pattern "$#0.00". (return index 0 and error index |
| 2030 // 1). |
| 2031 if (!sawDigit && digitCount == 0) { |
| 2032 parsePosition.setIndex(oldStart); |
| 2033 parsePosition.setErrorIndex(oldStart); |
| 2034 return FALSE; |
| 2035 } |
| 2036 } |
| 2037 |
| 2038 // Match padding before suffix |
| 2039 if (fFormatWidth > 0 && fPadPosition == kPadBeforeSuffix) { |
| 2040 position = skipPadding(text, position); |
| 2041 } |
| 2042 |
| 2043 // Match positive and negative suffixes; prefer longest match. |
| 2044 if (posMatch >= 0) { |
| 2045 posMatch = compareAffix(text, position, FALSE, FALSE, posSuffix, currenc
yParsing, type, currency); |
| 2046 } |
| 2047 if (negMatch >= 0) { |
| 2048 negMatch = compareAffix(text, position, TRUE, FALSE, negSuffix, currency
Parsing, type, currency); |
| 2049 } |
| 2050 if (posMatch >= 0 && negMatch >= 0) { |
| 2051 if (posMatch > negMatch) { |
| 2052 negMatch = -1; |
| 2053 } else if (negMatch > posMatch) { |
| 2054 posMatch = -1; |
| 2055 } |
| 2056 } |
| 2057 |
| 2058 // Fail if neither or both |
| 2059 if ((posMatch >= 0) == (negMatch >= 0)) { |
| 2060 parsePosition.setErrorIndex(position); |
| 2061 return FALSE; |
| 2062 } |
| 2063 |
| 2064 position += (posMatch>=0 ? posMatch : negMatch); |
| 2065 |
| 2066 // Match padding before suffix |
| 2067 if (fFormatWidth > 0 && fPadPosition == kPadAfterSuffix) { |
| 2068 position = skipPadding(text, position); |
| 2069 } |
| 2070 |
| 2071 parsePosition.setIndex(position); |
| 2072 |
| 2073 parsedNum.data()[0] = (posMatch >= 0) ? '+' : '-'; |
| 2074 |
| 2075 if(parsePosition.getIndex() == oldStart) |
| 2076 { |
| 2077 parsePosition.setErrorIndex(position); |
| 2078 return FALSE; |
| 2079 } |
| 2080 digits.set(parsedNum.toStringPiece(), err); |
| 2081 |
| 2082 if (U_FAILURE(err)) { |
| 2083 parsePosition.setErrorIndex(position); |
| 2084 return FALSE; |
| 2085 } |
| 2086 return TRUE; |
| 2087 } |
| 2088 |
| 2089 /** |
| 2090 * Starting at position, advance past a run of pad characters, if any. |
| 2091 * Return the index of the first character after position that is not a pad |
| 2092 * character. Result is >= position. |
| 2093 */ |
| 2094 int32_t DecimalFormat::skipPadding(const UnicodeString& text, int32_t position)
const { |
| 2095 int32_t padLen = U16_LENGTH(fPad); |
| 2096 while (position < text.length() && |
| 2097 text.char32At(position) == fPad) { |
| 2098 position += padLen; |
| 2099 } |
| 2100 return position; |
| 2101 } |
| 2102 |
| 2103 /** |
| 2104 * Return the length matched by the given affix, or -1 if none. |
| 2105 * Runs of white space in the affix, match runs of white space in |
| 2106 * the input. Pattern white space and input white space are |
| 2107 * determined differently; see code. |
| 2108 * @param text input text |
| 2109 * @param pos offset into input at which to begin matching |
| 2110 * @param isNegative |
| 2111 * @param isPrefix |
| 2112 * @param affixPat affix pattern used for currency affix comparison. |
| 2113 * @param currencyParsing whether it is currency parsing or not |
| 2114 * @param type the currency type to parse against, LONG_NAME only or not. |
| 2115 * @param currency return value for parsed currency, for generic |
| 2116 * currency parsing mode, or null for normal parsing. In generic |
| 2117 * currency parsing mode, any currency is parsed, not just the |
| 2118 * currency that this formatter is set to. |
| 2119 * @return length of input that matches, or -1 if match failure |
| 2120 */ |
| 2121 int32_t DecimalFormat::compareAffix(const UnicodeString& text, |
| 2122 int32_t pos, |
| 2123 UBool isNegative, |
| 2124 UBool isPrefix, |
| 2125 const UnicodeString* affixPat, |
| 2126 UBool currencyParsing, |
| 2127 int8_t type, |
| 2128 UChar* currency) const |
| 2129 { |
| 2130 const UnicodeString *patternToCompare; |
| 2131 if (fCurrencyChoice != NULL || currency != NULL || |
| 2132 (fCurrencySignCount > fgCurrencySignCountZero && currencyParsing)) { |
| 2133 |
| 2134 if (affixPat != NULL) { |
| 2135 return compareComplexAffix(*affixPat, text, pos, type, currency); |
| 2136 } |
| 2137 } |
| 2138 |
| 2139 if (isNegative) { |
| 2140 if (isPrefix) { |
| 2141 patternToCompare = &fNegativePrefix; |
| 2142 } |
| 2143 else { |
| 2144 patternToCompare = &fNegativeSuffix; |
| 2145 } |
| 2146 } |
| 2147 else { |
| 2148 if (isPrefix) { |
| 2149 patternToCompare = &fPositivePrefix; |
| 2150 } |
| 2151 else { |
| 2152 patternToCompare = &fPositiveSuffix; |
| 2153 } |
| 2154 } |
| 2155 return compareSimpleAffix(*patternToCompare, text, pos); |
| 2156 } |
| 2157 |
| 2158 /** |
| 2159 * Return the length matched by the given affix, or -1 if none. |
| 2160 * Runs of white space in the affix, match runs of white space in |
| 2161 * the input. Pattern white space and input white space are |
| 2162 * determined differently; see code. |
| 2163 * @param affix pattern string, taken as a literal |
| 2164 * @param input input text |
| 2165 * @param pos offset into input at which to begin matching |
| 2166 * @return length of input that matches, or -1 if match failure |
| 2167 */ |
| 2168 int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, |
| 2169 const UnicodeString& input, |
| 2170 int32_t pos) { |
| 2171 int32_t start = pos; |
| 2172 for (int32_t i=0; i<affix.length(); ) { |
| 2173 UChar32 c = affix.char32At(i); |
| 2174 int32_t len = U16_LENGTH(c); |
| 2175 if (uprv_isRuleWhiteSpace(c)) { |
| 2176 // We may have a pattern like: \u200F \u0020 |
| 2177 // and input text like: \u200F \u0020 |
| 2178 // Note that U+200F and U+0020 are RuleWhiteSpace but only |
| 2179 // U+0020 is UWhiteSpace. So we have to first do a direct |
| 2180 // match of the run of RULE whitespace in the pattern, |
| 2181 // then match any extra characters. |
| 2182 UBool literalMatch = FALSE; |
| 2183 while (pos < input.length() && |
| 2184 input.char32At(pos) == c) { |
| 2185 literalMatch = TRUE; |
| 2186 i += len; |
| 2187 pos += len; |
| 2188 if (i == affix.length()) { |
| 2189 break; |
| 2190 } |
| 2191 c = affix.char32At(i); |
| 2192 len = U16_LENGTH(c); |
| 2193 if (!uprv_isRuleWhiteSpace(c)) { |
| 2194 break; |
| 2195 } |
| 2196 } |
| 2197 |
| 2198 // Advance over run in pattern |
| 2199 i = skipRuleWhiteSpace(affix, i); |
| 2200 |
| 2201 // Advance over run in input text |
| 2202 // Must see at least one white space char in input, |
| 2203 // unless we've already matched some characters literally. |
| 2204 int32_t s = pos; |
| 2205 pos = skipUWhiteSpace(input, pos); |
| 2206 if (pos == s && !literalMatch) { |
| 2207 return -1; |
| 2208 } |
| 2209 |
| 2210 // If we skip UWhiteSpace in the input text, we need to skip it in t
he pattern. |
| 2211 // Otherwise, the previous lines may have skipped over text (such as
U+00A0) that |
| 2212 // is also in the affix. |
| 2213 i = skipUWhiteSpace(affix, i); |
| 2214 } else { |
| 2215 if (pos < input.length() && |
| 2216 input.char32At(pos) == c) { |
| 2217 i += len; |
| 2218 pos += len; |
| 2219 } else { |
| 2220 return -1; |
| 2221 } |
| 2222 } |
| 2223 } |
| 2224 return pos - start; |
| 2225 } |
| 2226 |
| 2227 /** |
| 2228 * Skip over a run of zero or more isRuleWhiteSpace() characters at |
| 2229 * pos in text. |
| 2230 */ |
| 2231 int32_t DecimalFormat::skipRuleWhiteSpace(const UnicodeString& text, int32_t pos
) { |
| 2232 while (pos < text.length()) { |
| 2233 UChar32 c = text.char32At(pos); |
| 2234 if (!uprv_isRuleWhiteSpace(c)) { |
| 2235 break; |
| 2236 } |
| 2237 pos += U16_LENGTH(c); |
| 2238 } |
| 2239 return pos; |
| 2240 } |
| 2241 |
| 2242 /** |
| 2243 * Skip over a run of zero or more isUWhiteSpace() characters at pos |
| 2244 * in text. |
| 2245 */ |
| 2246 int32_t DecimalFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) { |
| 2247 while (pos < text.length()) { |
| 2248 UChar32 c = text.char32At(pos); |
| 2249 if (!u_isUWhiteSpace(c)) { |
| 2250 break; |
| 2251 } |
| 2252 pos += U16_LENGTH(c); |
| 2253 } |
| 2254 return pos; |
| 2255 } |
| 2256 |
| 2257 /** |
| 2258 * Return the length matched by the given affix, or -1 if none. |
| 2259 * @param affixPat pattern string |
| 2260 * @param input input text |
| 2261 * @param pos offset into input at which to begin matching |
| 2262 * @param type the currency type to parse against, LONG_NAME only or not. |
| 2263 * @param currency return value for parsed currency, for generic |
| 2264 * currency parsing mode, or null for normal parsing. In generic |
| 2265 * currency parsing mode, any currency is parsed, not just the |
| 2266 * currency that this formatter is set to. |
| 2267 * @return length of input that matches, or -1 if match failure |
| 2268 */ |
| 2269 int32_t DecimalFormat::compareComplexAffix(const UnicodeString& affixPat, |
| 2270 const UnicodeString& text, |
| 2271 int32_t pos, |
| 2272 int8_t type, |
| 2273 UChar* currency) const |
| 2274 { |
| 2275 int32_t start = pos; |
| 2276 U_ASSERT(currency != NULL || |
| 2277 (fCurrencyChoice != NULL && *getCurrency() != 0) || |
| 2278 fCurrencySignCount > fgCurrencySignCountZero); |
| 2279 |
| 2280 for (int32_t i=0; |
| 2281 i<affixPat.length() && pos >= 0; ) { |
| 2282 UChar32 c = affixPat.char32At(i); |
| 2283 i += U16_LENGTH(c); |
| 2284 |
| 2285 if (c == kQuote) { |
| 2286 U_ASSERT(i <= affixPat.length()); |
| 2287 c = affixPat.char32At(i); |
| 2288 i += U16_LENGTH(c); |
| 2289 |
| 2290 const UnicodeString* affix = NULL; |
| 2291 |
| 2292 switch (c) { |
| 2293 case kCurrencySign: { |
| 2294 // since the currency names in choice format is saved |
| 2295 // the same way as other currency names, |
| 2296 // do not need to do currency choice parsing here. |
| 2297 // the general currency parsing parse against all names, |
| 2298 // including names in choice format. |
| 2299 UBool intl = i<affixPat.length() && |
| 2300 affixPat.char32At(i) == kCurrencySign; |
| 2301 if (intl) { |
| 2302 ++i; |
| 2303 } |
| 2304 UBool plural = i<affixPat.length() && |
| 2305 affixPat.char32At(i) == kCurrencySign; |
| 2306 if (plural) { |
| 2307 ++i; |
| 2308 intl = FALSE; |
| 2309 } |
| 2310 // Parse generic currency -- anything for which we |
| 2311 // have a display name, or any 3-letter ISO code. |
| 2312 // Try to parse display name for our locale; first |
| 2313 // determine our locale. |
| 2314 const char* loc = fCurrencyPluralInfo->getLocale().getName(); |
| 2315 ParsePosition ppos(pos); |
| 2316 UChar curr[4]; |
| 2317 UErrorCode ec = U_ZERO_ERROR; |
| 2318 // Delegate parse of display name => ISO code to Currency |
| 2319 uprv_parseCurrency(loc, text, ppos, type, curr, ec); |
| 2320 |
| 2321 // If parse succeeds, populate currency[0] |
| 2322 if (U_SUCCESS(ec) && ppos.getIndex() != pos) { |
| 2323 if (currency) { |
| 2324 u_strcpy(currency, curr); |
| 2325 } |
| 2326 pos = ppos.getIndex(); |
| 2327 } else { |
| 2328 pos = -1; |
| 2329 } |
| 2330 continue; |
| 2331 } |
| 2332 case kPatternPercent: |
| 2333 affix = &getConstSymbol(DecimalFormatSymbols::kPercentSymbol); |
| 2334 break; |
| 2335 case kPatternPerMill: |
| 2336 affix = &getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); |
| 2337 break; |
| 2338 case kPatternPlus: |
| 2339 affix = &getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); |
| 2340 break; |
| 2341 case kPatternMinus: |
| 2342 affix = &getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); |
| 2343 break; |
| 2344 default: |
| 2345 // fall through to affix!=0 test, which will fail |
| 2346 break; |
| 2347 } |
| 2348 |
| 2349 if (affix != NULL) { |
| 2350 pos = match(text, pos, *affix); |
| 2351 continue; |
| 2352 } |
| 2353 } |
| 2354 |
| 2355 pos = match(text, pos, c); |
| 2356 if (uprv_isRuleWhiteSpace(c)) { |
| 2357 i = skipRuleWhiteSpace(affixPat, i); |
| 2358 } |
| 2359 } |
| 2360 return pos - start; |
| 2361 } |
| 2362 |
| 2363 /** |
| 2364 * Match a single character at text[pos] and return the index of the |
| 2365 * next character upon success. Return -1 on failure. If |
| 2366 * isRuleWhiteSpace(ch) then match a run of white space in text. |
| 2367 */ |
| 2368 int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, UChar32 ch)
{ |
| 2369 if (uprv_isRuleWhiteSpace(ch)) { |
| 2370 // Advance over run of white space in input text |
| 2371 // Must see at least one white space char in input |
| 2372 int32_t s = pos; |
| 2373 pos = skipRuleWhiteSpace(text, pos); |
| 2374 if (pos == s) { |
| 2375 return -1; |
| 2376 } |
| 2377 return pos; |
| 2378 } |
| 2379 return (pos >= 0 && text.char32At(pos) == ch) ? |
| 2380 (pos + U16_LENGTH(ch)) : -1; |
| 2381 } |
| 2382 |
| 2383 /** |
| 2384 * Match a string at text[pos] and return the index of the next |
| 2385 * character upon success. Return -1 on failure. Match a run of |
| 2386 * white space in str with a run of white space in text. |
| 2387 */ |
| 2388 int32_t DecimalFormat::match(const UnicodeString& text, int32_t pos, const Unico
deString& str) { |
| 2389 for (int32_t i=0; i<str.length() && pos >= 0; ) { |
| 2390 UChar32 ch = str.char32At(i); |
| 2391 i += U16_LENGTH(ch); |
| 2392 if (uprv_isRuleWhiteSpace(ch)) { |
| 2393 i = skipRuleWhiteSpace(str, i); |
| 2394 } |
| 2395 pos = match(text, pos, ch); |
| 2396 } |
| 2397 return pos; |
| 2398 } |
| 2399 |
| 2400 //------------------------------------------------------------------------------ |
| 2401 // Gets the pointer to the localized decimal format symbols |
| 2402 |
| 2403 const DecimalFormatSymbols* |
| 2404 DecimalFormat::getDecimalFormatSymbols() const |
| 2405 { |
| 2406 return fSymbols; |
| 2407 } |
| 2408 |
| 2409 //------------------------------------------------------------------------------ |
| 2410 // De-owning the current localized symbols and adopt the new symbols. |
| 2411 |
| 2412 void |
| 2413 DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) |
| 2414 { |
| 2415 if (symbolsToAdopt == NULL) { |
| 2416 return; // do not allow caller to set fSymbols to NULL |
| 2417 } |
| 2418 |
| 2419 UBool sameSymbols = FALSE; |
| 2420 if (fSymbols != NULL) { |
| 2421 sameSymbols = (UBool)(getConstSymbol(DecimalFormatSymbols::kCurrencySymb
ol) == |
| 2422 symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kCurrencySymbol
) && |
| 2423 getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) == |
| 2424 symbolsToAdopt->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySy
mbol)); |
| 2425 delete fSymbols; |
| 2426 } |
| 2427 |
| 2428 fSymbols = symbolsToAdopt; |
| 2429 if (!sameSymbols) { |
| 2430 // If the currency symbols are the same, there is no need to recalculate
. |
| 2431 setCurrencyForSymbols(); |
| 2432 } |
| 2433 expandAffixes(NULL); |
| 2434 } |
| 2435 //------------------------------------------------------------------------------ |
| 2436 // Setting the symbols is equlivalent to adopting a newly created localized |
| 2437 // symbols. |
| 2438 |
| 2439 void |
| 2440 DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) |
| 2441 { |
| 2442 adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); |
| 2443 } |
| 2444 |
| 2445 |
| 2446 const CurrencyPluralInfo* |
| 2447 DecimalFormat::getCurrencyPluralInfo(void) const |
| 2448 { |
| 2449 return fCurrencyPluralInfo; |
| 2450 } |
| 2451 |
| 2452 |
| 2453 void |
| 2454 DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) |
| 2455 { |
| 2456 if (toAdopt != NULL) { |
| 2457 delete fCurrencyPluralInfo; |
| 2458 fCurrencyPluralInfo = toAdopt; |
| 2459 // re-set currency affix patterns and currency affixes. |
| 2460 if (fCurrencySignCount > fgCurrencySignCountZero) { |
| 2461 UErrorCode status = U_ZERO_ERROR; |
| 2462 if (fAffixPatternsForCurrency) { |
| 2463 deleteHashForAffixPattern(); |
| 2464 } |
| 2465 setupCurrencyAffixPatterns(status); |
| 2466 if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) { |
| 2467 // only setup the affixes of the plural pattern. |
| 2468 setupCurrencyAffixes(fFormatPattern, FALSE, TRUE, status); |
| 2469 } |
| 2470 } |
| 2471 } |
| 2472 } |
| 2473 |
| 2474 void |
| 2475 DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) |
| 2476 { |
| 2477 adoptCurrencyPluralInfo(info.clone()); |
| 2478 } |
| 2479 |
| 2480 |
| 2481 /** |
| 2482 * Update the currency object to match the symbols. This method |
| 2483 * is used only when the caller has passed in a symbols object |
| 2484 * that may not be the default object for its locale. |
| 2485 */ |
| 2486 void |
| 2487 DecimalFormat::setCurrencyForSymbols() { |
| 2488 /*Bug 4212072 |
| 2489 Update the affix strings accroding to symbols in order to keep |
| 2490 the affix strings up to date. |
| 2491 [Richard/GCL] |
| 2492 */ |
| 2493 |
| 2494 // With the introduction of the Currency object, the currency |
| 2495 // symbols in the DFS object are ignored. For backward |
| 2496 // compatibility, we check any explicitly set DFS object. If it |
| 2497 // is a default symbols object for its locale, we change the |
| 2498 // currency object to one for that locale. If it is custom, |
| 2499 // we set the currency to null. |
| 2500 UErrorCode ec = U_ZERO_ERROR; |
| 2501 const UChar* c = NULL; |
| 2502 const char* loc = fSymbols->getLocale().getName(); |
| 2503 UChar intlCurrencySymbol[4]; |
| 2504 ucurr_forLocale(loc, intlCurrencySymbol, 4, &ec); |
| 2505 UnicodeString currencySymbol; |
| 2506 |
| 2507 uprv_getStaticCurrencyName(intlCurrencySymbol, loc, currencySymbol, ec); |
| 2508 if (U_SUCCESS(ec) |
| 2509 && getConstSymbol(DecimalFormatSymbols::kCurrencySymbol) == currencySymb
ol |
| 2510 && getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol) == intlCurr
encySymbol) |
| 2511 { |
| 2512 // Trap an error in mapping locale to currency. If we can't |
| 2513 // map, then don't fail and set the currency to "". |
| 2514 c = intlCurrencySymbol; |
| 2515 } |
| 2516 ec = U_ZERO_ERROR; // reset local error code! |
| 2517 setCurrencyInternally(c, ec); |
| 2518 } |
| 2519 |
| 2520 |
| 2521 //------------------------------------------------------------------------------ |
| 2522 // Gets the positive prefix of the number pattern. |
| 2523 |
| 2524 UnicodeString& |
| 2525 DecimalFormat::getPositivePrefix(UnicodeString& result) const |
| 2526 { |
| 2527 result = fPositivePrefix; |
| 2528 return result; |
| 2529 } |
| 2530 |
| 2531 //------------------------------------------------------------------------------ |
| 2532 // Sets the positive prefix of the number pattern. |
| 2533 |
| 2534 void |
| 2535 DecimalFormat::setPositivePrefix(const UnicodeString& newValue) |
| 2536 { |
| 2537 fPositivePrefix = newValue; |
| 2538 delete fPosPrefixPattern; |
| 2539 fPosPrefixPattern = 0; |
| 2540 } |
| 2541 |
| 2542 //------------------------------------------------------------------------------ |
| 2543 // Gets the negative prefix of the number pattern. |
| 2544 |
| 2545 UnicodeString& |
| 2546 DecimalFormat::getNegativePrefix(UnicodeString& result) const |
| 2547 { |
| 2548 result = fNegativePrefix; |
| 2549 return result; |
| 2550 } |
| 2551 |
| 2552 //------------------------------------------------------------------------------ |
| 2553 // Gets the negative prefix of the number pattern. |
| 2554 |
| 2555 void |
| 2556 DecimalFormat::setNegativePrefix(const UnicodeString& newValue) |
| 2557 { |
| 2558 fNegativePrefix = newValue; |
| 2559 delete fNegPrefixPattern; |
| 2560 fNegPrefixPattern = 0; |
| 2561 } |
| 2562 |
| 2563 //------------------------------------------------------------------------------ |
| 2564 // Gets the positive suffix of the number pattern. |
| 2565 |
| 2566 UnicodeString& |
| 2567 DecimalFormat::getPositiveSuffix(UnicodeString& result) const |
| 2568 { |
| 2569 result = fPositiveSuffix; |
| 2570 return result; |
| 2571 } |
| 2572 |
| 2573 //------------------------------------------------------------------------------ |
| 2574 // Sets the positive suffix of the number pattern. |
| 2575 |
| 2576 void |
| 2577 DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) |
| 2578 { |
| 2579 fPositiveSuffix = newValue; |
| 2580 delete fPosSuffixPattern; |
| 2581 fPosSuffixPattern = 0; |
| 2582 } |
| 2583 |
| 2584 //------------------------------------------------------------------------------ |
| 2585 // Gets the negative suffix of the number pattern. |
| 2586 |
| 2587 UnicodeString& |
| 2588 DecimalFormat::getNegativeSuffix(UnicodeString& result) const |
| 2589 { |
| 2590 result = fNegativeSuffix; |
| 2591 return result; |
| 2592 } |
| 2593 |
| 2594 //------------------------------------------------------------------------------ |
| 2595 // Sets the negative suffix of the number pattern. |
| 2596 |
| 2597 void |
| 2598 DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) |
| 2599 { |
| 2600 fNegativeSuffix = newValue; |
| 2601 delete fNegSuffixPattern; |
| 2602 fNegSuffixPattern = 0; |
| 2603 } |
| 2604 |
| 2605 //------------------------------------------------------------------------------ |
| 2606 // Gets the multiplier of the number pattern. |
| 2607 // Multipliers are stored as decimal numbers (DigitLists) because that |
| 2608 // is the most convenient for muliplying or dividing the numbers to be form
atted. |
| 2609 // A NULL multiplier implies one, and the scaling operations are skipped. |
| 2610 |
| 2611 int32_t |
| 2612 DecimalFormat::getMultiplier() const |
| 2613 { |
| 2614 if (fMultiplier == NULL) { |
| 2615 return 1; |
| 2616 } else { |
| 2617 return fMultiplier->getLong(); |
| 2618 } |
| 2619 } |
| 2620 |
| 2621 //------------------------------------------------------------------------------ |
| 2622 // Sets the multiplier of the number pattern. |
| 2623 void |
| 2624 DecimalFormat::setMultiplier(int32_t newValue) |
| 2625 { |
| 2626 // if (newValue == 0) { |
| 2627 // throw new IllegalArgumentException("Bad multiplier: " + newValue); |
| 2628 // } |
| 2629 if (newValue == 0) { |
| 2630 newValue = 1; // one being the benign default value for a multiplier
. |
| 2631 } |
| 2632 if (newValue == 1) { |
| 2633 delete fMultiplier; |
| 2634 fMultiplier = NULL; |
| 2635 } else { |
| 2636 if (fMultiplier == NULL) { |
| 2637 fMultiplier = new DigitList; |
| 2638 } |
| 2639 if (fMultiplier != NULL) { |
| 2640 fMultiplier->set(newValue); |
| 2641 } |
| 2642 } |
| 2643 } |
| 2644 |
| 2645 /** |
| 2646 * Get the rounding increment. |
| 2647 * @return A positive rounding increment, or 0.0 if rounding |
| 2648 * is not in effect. |
| 2649 * @see #setRoundingIncrement |
| 2650 * @see #getRoundingMode |
| 2651 * @see #setRoundingMode |
| 2652 */ |
| 2653 double DecimalFormat::getRoundingIncrement() const { |
| 2654 if (fRoundingIncrement == NULL) { |
| 2655 return 0.0; |
| 2656 } else { |
| 2657 return fRoundingIncrement->getDouble(); |
| 2658 } |
| 2659 } |
| 2660 |
| 2661 /** |
| 2662 * Set the rounding increment. This method also controls whether |
| 2663 * rounding is enabled. |
| 2664 * @param newValue A positive rounding increment, or 0.0 to disable rounding. |
| 2665 * Negative increments are equivalent to 0.0. |
| 2666 * @see #getRoundingIncrement |
| 2667 * @see #getRoundingMode |
| 2668 * @see #setRoundingMode |
| 2669 */ |
| 2670 void DecimalFormat::setRoundingIncrement(double newValue) { |
| 2671 if (newValue > 0.0) { |
| 2672 if (fRoundingIncrement == NULL) { |
| 2673 fRoundingIncrement = new DigitList(); |
| 2674 } |
| 2675 if (fRoundingIncrement != NULL) { |
| 2676 fRoundingIncrement->set(newValue); |
| 2677 return; |
| 2678 } |
| 2679 } |
| 2680 // These statements are executed if newValue is less than 0.0 |
| 2681 // or fRoundingIncrement could not be created. |
| 2682 delete fRoundingIncrement; |
| 2683 fRoundingIncrement = NULL; |
| 2684 } |
| 2685 |
| 2686 /** |
| 2687 * Get the rounding mode. |
| 2688 * @return A rounding mode |
| 2689 * @see #setRoundingIncrement |
| 2690 * @see #getRoundingIncrement |
| 2691 * @see #setRoundingMode |
| 2692 */ |
| 2693 DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() const { |
| 2694 return fRoundingMode; |
| 2695 } |
| 2696 |
| 2697 /** |
| 2698 * Set the rounding mode. This has no effect unless the rounding |
| 2699 * increment is greater than zero. |
| 2700 * @param roundingMode A rounding mode |
| 2701 * @see #setRoundingIncrement |
| 2702 * @see #getRoundingIncrement |
| 2703 * @see #getRoundingMode |
| 2704 */ |
| 2705 void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { |
| 2706 fRoundingMode = roundingMode; |
| 2707 } |
| 2708 |
| 2709 /** |
| 2710 * Get the width to which the output of <code>format()</code> is padded. |
| 2711 * @return the format width, or zero if no padding is in effect |
| 2712 * @see #setFormatWidth |
| 2713 * @see #getPadCharacter |
| 2714 * @see #setPadCharacter |
| 2715 * @see #getPadPosition |
| 2716 * @see #setPadPosition |
| 2717 */ |
| 2718 int32_t DecimalFormat::getFormatWidth() const { |
| 2719 return fFormatWidth; |
| 2720 } |
| 2721 |
| 2722 /** |
| 2723 * Set the width to which the output of <code>format()</code> is padded. |
| 2724 * This method also controls whether padding is enabled. |
| 2725 * @param width the width to which to pad the result of |
| 2726 * <code>format()</code>, or zero to disable padding. A negative |
| 2727 * width is equivalent to 0. |
| 2728 * @see #getFormatWidth |
| 2729 * @see #getPadCharacter |
| 2730 * @see #setPadCharacter |
| 2731 * @see #getPadPosition |
| 2732 * @see #setPadPosition |
| 2733 */ |
| 2734 void DecimalFormat::setFormatWidth(int32_t width) { |
| 2735 fFormatWidth = (width > 0) ? width : 0; |
| 2736 } |
| 2737 |
| 2738 UnicodeString DecimalFormat::getPadCharacterString() const { |
| 2739 return fPad; |
| 2740 } |
| 2741 |
| 2742 void DecimalFormat::setPadCharacter(const UnicodeString &padChar) { |
| 2743 if (padChar.length() > 0) { |
| 2744 fPad = padChar.char32At(0); |
| 2745 } |
| 2746 else { |
| 2747 fPad = kDefaultPad; |
| 2748 } |
| 2749 } |
| 2750 |
| 2751 /** |
| 2752 * Get the position at which padding will take place. This is the location |
| 2753 * at which padding will be inserted if the result of <code>format()</code> |
| 2754 * is shorter than the format width. |
| 2755 * @return the pad position, one of <code>kPadBeforePrefix</code>, |
| 2756 * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or |
| 2757 * <code>kPadAfterSuffix</code>. |
| 2758 * @see #setFormatWidth |
| 2759 * @see #getFormatWidth |
| 2760 * @see #setPadCharacter |
| 2761 * @see #getPadCharacter |
| 2762 * @see #setPadPosition |
| 2763 * @see #kPadBeforePrefix |
| 2764 * @see #kPadAfterPrefix |
| 2765 * @see #kPadBeforeSuffix |
| 2766 * @see #kPadAfterSuffix |
| 2767 */ |
| 2768 DecimalFormat::EPadPosition DecimalFormat::getPadPosition() const { |
| 2769 return fPadPosition; |
| 2770 } |
| 2771 |
| 2772 /** |
| 2773 * <strong><font face=helvetica color=red>NEW</font></strong> |
| 2774 * Set the position at which padding will take place. This is the location |
| 2775 * at which padding will be inserted if the result of <code>format()</code> |
| 2776 * is shorter than the format width. This has no effect unless padding is |
| 2777 * enabled. |
| 2778 * @param padPos the pad position, one of <code>kPadBeforePrefix</code>, |
| 2779 * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or |
| 2780 * <code>kPadAfterSuffix</code>. |
| 2781 * @see #setFormatWidth |
| 2782 * @see #getFormatWidth |
| 2783 * @see #setPadCharacter |
| 2784 * @see #getPadCharacter |
| 2785 * @see #getPadPosition |
| 2786 * @see #kPadBeforePrefix |
| 2787 * @see #kPadAfterPrefix |
| 2788 * @see #kPadBeforeSuffix |
| 2789 * @see #kPadAfterSuffix |
| 2790 */ |
| 2791 void DecimalFormat::setPadPosition(EPadPosition padPos) { |
| 2792 fPadPosition = padPos; |
| 2793 } |
| 2794 |
| 2795 /** |
| 2796 * Return whether or not scientific notation is used. |
| 2797 * @return TRUE if this object formats and parses scientific notation |
| 2798 * @see #setScientificNotation |
| 2799 * @see #getMinimumExponentDigits |
| 2800 * @see #setMinimumExponentDigits |
| 2801 * @see #isExponentSignAlwaysShown |
| 2802 * @see #setExponentSignAlwaysShown |
| 2803 */ |
| 2804 UBool DecimalFormat::isScientificNotation() { |
| 2805 return fUseExponentialNotation; |
| 2806 } |
| 2807 |
| 2808 /** |
| 2809 * Set whether or not scientific notation is used. |
| 2810 * @param useScientific TRUE if this object formats and parses scientific |
| 2811 * notation |
| 2812 * @see #isScientificNotation |
| 2813 * @see #getMinimumExponentDigits |
| 2814 * @see #setMinimumExponentDigits |
| 2815 * @see #isExponentSignAlwaysShown |
| 2816 * @see #setExponentSignAlwaysShown |
| 2817 */ |
| 2818 void DecimalFormat::setScientificNotation(UBool useScientific) { |
| 2819 fUseExponentialNotation = useScientific; |
| 2820 } |
| 2821 |
| 2822 /** |
| 2823 * Return the minimum exponent digits that will be shown. |
| 2824 * @return the minimum exponent digits that will be shown |
| 2825 * @see #setScientificNotation |
| 2826 * @see #isScientificNotation |
| 2827 * @see #setMinimumExponentDigits |
| 2828 * @see #isExponentSignAlwaysShown |
| 2829 * @see #setExponentSignAlwaysShown |
| 2830 */ |
| 2831 int8_t DecimalFormat::getMinimumExponentDigits() const { |
| 2832 return fMinExponentDigits; |
| 2833 } |
| 2834 |
| 2835 /** |
| 2836 * Set the minimum exponent digits that will be shown. This has no |
| 2837 * effect unless scientific notation is in use. |
| 2838 * @param minExpDig a value >= 1 indicating the fewest exponent digits |
| 2839 * that will be shown. Values less than 1 will be treated as 1. |
| 2840 * @see #setScientificNotation |
| 2841 * @see #isScientificNotation |
| 2842 * @see #getMinimumExponentDigits |
| 2843 * @see #isExponentSignAlwaysShown |
| 2844 * @see #setExponentSignAlwaysShown |
| 2845 */ |
| 2846 void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { |
| 2847 fMinExponentDigits = (int8_t)((minExpDig > 0) ? minExpDig : 1); |
| 2848 } |
| 2849 |
| 2850 /** |
| 2851 * Return whether the exponent sign is always shown. |
| 2852 * @return TRUE if the exponent is always prefixed with either the |
| 2853 * localized minus sign or the localized plus sign, false if only negative |
| 2854 * exponents are prefixed with the localized minus sign. |
| 2855 * @see #setScientificNotation |
| 2856 * @see #isScientificNotation |
| 2857 * @see #setMinimumExponentDigits |
| 2858 * @see #getMinimumExponentDigits |
| 2859 * @see #setExponentSignAlwaysShown |
| 2860 */ |
| 2861 UBool DecimalFormat::isExponentSignAlwaysShown() { |
| 2862 return fExponentSignAlwaysShown; |
| 2863 } |
| 2864 |
| 2865 /** |
| 2866 * Set whether the exponent sign is always shown. This has no effect |
| 2867 * unless scientific notation is in use. |
| 2868 * @param expSignAlways TRUE if the exponent is always prefixed with either |
| 2869 * the localized minus sign or the localized plus sign, false if only |
| 2870 * negative exponents are prefixed with the localized minus sign. |
| 2871 * @see #setScientificNotation |
| 2872 * @see #isScientificNotation |
| 2873 * @see #setMinimumExponentDigits |
| 2874 * @see #getMinimumExponentDigits |
| 2875 * @see #isExponentSignAlwaysShown |
| 2876 */ |
| 2877 void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { |
| 2878 fExponentSignAlwaysShown = expSignAlways; |
| 2879 } |
| 2880 |
| 2881 //------------------------------------------------------------------------------ |
| 2882 // Gets the grouping size of the number pattern. For example, thousand or 10 |
| 2883 // thousand groupings. |
| 2884 |
| 2885 int32_t |
| 2886 DecimalFormat::getGroupingSize() const |
| 2887 { |
| 2888 return fGroupingSize; |
| 2889 } |
| 2890 |
| 2891 //------------------------------------------------------------------------------ |
| 2892 // Gets the grouping size of the number pattern. |
| 2893 |
| 2894 void |
| 2895 DecimalFormat::setGroupingSize(int32_t newValue) |
| 2896 { |
| 2897 fGroupingSize = newValue; |
| 2898 } |
| 2899 |
| 2900 //------------------------------------------------------------------------------ |
| 2901 |
| 2902 int32_t |
| 2903 DecimalFormat::getSecondaryGroupingSize() const |
| 2904 { |
| 2905 return fGroupingSize2; |
| 2906 } |
| 2907 |
| 2908 //------------------------------------------------------------------------------ |
| 2909 |
| 2910 void |
| 2911 DecimalFormat::setSecondaryGroupingSize(int32_t newValue) |
| 2912 { |
| 2913 fGroupingSize2 = newValue; |
| 2914 } |
| 2915 |
| 2916 //------------------------------------------------------------------------------ |
| 2917 // Checks if to show the decimal separator. |
| 2918 |
| 2919 UBool |
| 2920 DecimalFormat::isDecimalSeparatorAlwaysShown() const |
| 2921 { |
| 2922 return fDecimalSeparatorAlwaysShown; |
| 2923 } |
| 2924 |
| 2925 //------------------------------------------------------------------------------ |
| 2926 // Sets to always show the decimal separator. |
| 2927 |
| 2928 void |
| 2929 DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) |
| 2930 { |
| 2931 fDecimalSeparatorAlwaysShown = newValue; |
| 2932 } |
| 2933 |
| 2934 //------------------------------------------------------------------------------ |
| 2935 // Emits the pattern of this DecimalFormat instance. |
| 2936 |
| 2937 UnicodeString& |
| 2938 DecimalFormat::toPattern(UnicodeString& result) const |
| 2939 { |
| 2940 return toPattern(result, FALSE); |
| 2941 } |
| 2942 |
| 2943 //------------------------------------------------------------------------------ |
| 2944 // Emits the localized pattern this DecimalFormat instance. |
| 2945 |
| 2946 UnicodeString& |
| 2947 DecimalFormat::toLocalizedPattern(UnicodeString& result) const |
| 2948 { |
| 2949 return toPattern(result, TRUE); |
| 2950 } |
| 2951 |
| 2952 //------------------------------------------------------------------------------ |
| 2953 /** |
| 2954 * Expand the affix pattern strings into the expanded affix strings. If any |
| 2955 * affix pattern string is null, do not expand it. This method should be |
| 2956 * called any time the symbols or the affix patterns change in order to keep |
| 2957 * the expanded affix strings up to date. |
| 2958 * This method also will be called before formatting if format currency |
| 2959 * plural names, since the plural name is not a static one, it is |
| 2960 * based on the currency plural count, the affix will be known only |
| 2961 * after the currency plural count is know. |
| 2962 * In which case, the parameter |
| 2963 * 'pluralCount' will be a non-null currency plural count. |
| 2964 * In all other cases, the 'pluralCount' is null, which means it is not needed. |
| 2965 */ |
| 2966 void DecimalFormat::expandAffixes(const UnicodeString* pluralCount) { |
| 2967 FieldPositionHandler none; |
| 2968 if (fPosPrefixPattern != 0) { |
| 2969 expandAffix(*fPosPrefixPattern, fPositivePrefix, 0, none, FALSE, pluralCou
nt); |
| 2970 } |
| 2971 if (fPosSuffixPattern != 0) { |
| 2972 expandAffix(*fPosSuffixPattern, fPositiveSuffix, 0, none, FALSE, pluralCou
nt); |
| 2973 } |
| 2974 if (fNegPrefixPattern != 0) { |
| 2975 expandAffix(*fNegPrefixPattern, fNegativePrefix, 0, none, FALSE, pluralCou
nt); |
| 2976 } |
| 2977 if (fNegSuffixPattern != 0) { |
| 2978 expandAffix(*fNegSuffixPattern, fNegativeSuffix, 0, none, FALSE, pluralCou
nt); |
| 2979 } |
| 2980 #ifdef FMT_DEBUG |
| 2981 UnicodeString s; |
| 2982 s.append("[") |
| 2983 .append(*fPosPrefixPattern).append("|").append(*fPosSuffixPattern) |
| 2984 .append(";") .append(*fNegPrefixPattern).append("|").append(*fNegSuffixP
attern) |
| 2985 .append("]->[") |
| 2986 .append(fPositivePrefix).append("|").append(fPositiveSuffix) |
| 2987 .append(";") .append(fNegativePrefix).append("|").append(fNegativeSuffix
) |
| 2988 .append("]\n"); |
| 2989 debugout(s); |
| 2990 #endif |
| 2991 } |
| 2992 |
| 2993 /** |
| 2994 * Expand an affix pattern into an affix string. All characters in the |
| 2995 * pattern are literal unless prefixed by kQuote. The following characters |
| 2996 * after kQuote are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, |
| 2997 * PATTERN_MINUS, and kCurrencySign. If kCurrencySign is doubled (kQuote + |
| 2998 * kCurrencySign + kCurrencySign), it is interpreted as an international |
| 2999 * currency sign. If CURRENCY_SIGN is tripled, it is interpreted as |
| 3000 * currency plural long names, such as "US Dollars". |
| 3001 * Any other character after a kQuote represents itself. |
| 3002 * kQuote must be followed by another character; kQuote may not occur by |
| 3003 * itself at the end of the pattern. |
| 3004 * |
| 3005 * This method is used in two distinct ways. First, it is used to expand |
| 3006 * the stored affix patterns into actual affixes. For this usage, doFormat |
| 3007 * must be false. Second, it is used to expand the stored affix patterns |
| 3008 * given a specific number (doFormat == true), for those rare cases in |
| 3009 * which a currency format references a ChoiceFormat (e.g., en_IN display |
| 3010 * name for INR). The number itself is taken from digitList. |
| 3011 * |
| 3012 * When used in the first way, this method has a side effect: It sets |
| 3013 * currencyChoice to a ChoiceFormat object, if the currency's display name |
| 3014 * in this locale is a ChoiceFormat pattern (very rare). It only does this |
| 3015 * if currencyChoice is null to start with. |
| 3016 * |
| 3017 * @param pattern the non-null, fPossibly empty pattern |
| 3018 * @param affix string to receive the expanded equivalent of pattern. |
| 3019 * Previous contents are deleted. |
| 3020 * @param doFormat if false, then the pattern will be expanded, and if a |
| 3021 * currency symbol is encountered that expands to a ChoiceFormat, the |
| 3022 * currencyChoice member variable will be initialized if it is null. If |
| 3023 * doFormat is true, then it is assumed that the currencyChoice has been |
| 3024 * created, and it will be used to format the value in digitList. |
| 3025 * @param pluralCount the plural count. It is only used for currency |
| 3026 * plural format. In which case, it is the plural |
| 3027 * count of the currency amount. For example, |
| 3028 * in en_US, it is the singular "one", or the plural |
| 3029 * "other". For all other cases, it is null, and |
| 3030 * is not being used. |
| 3031 */ |
| 3032 void DecimalFormat::expandAffix(const UnicodeString& pattern, |
| 3033 UnicodeString& affix, |
| 3034 double number, |
| 3035 FieldPositionHandler& handler, |
| 3036 UBool doFormat, |
| 3037 const UnicodeString* pluralCount) const { |
| 3038 affix.remove(); |
| 3039 for (int i=0; i<pattern.length(); ) { |
| 3040 UChar32 c = pattern.char32At(i); |
| 3041 i += U16_LENGTH(c); |
| 3042 if (c == kQuote) { |
| 3043 c = pattern.char32At(i); |
| 3044 i += U16_LENGTH(c); |
| 3045 int beginIdx = affix.length(); |
| 3046 switch (c) { |
| 3047 case kCurrencySign: { |
| 3048 // As of ICU 2.2 we use the currency object, and |
| 3049 // ignore the currency symbols in the DFS, unless |
| 3050 // we have a null currency object. This occurs if |
| 3051 // resurrecting a pre-2.2 object or if the user |
| 3052 // sets a custom DFS. |
| 3053 UBool intl = i<pattern.length() && |
| 3054 pattern.char32At(i) == kCurrencySign; |
| 3055 UBool plural = FALSE; |
| 3056 if (intl) { |
| 3057 ++i; |
| 3058 plural = i<pattern.length() && |
| 3059 pattern.char32At(i) == kCurrencySign; |
| 3060 if (plural) { |
| 3061 intl = FALSE; |
| 3062 ++i; |
| 3063 } |
| 3064 } |
| 3065 const UChar* currencyUChars = getCurrency(); |
| 3066 if (currencyUChars[0] != 0) { |
| 3067 UErrorCode ec = U_ZERO_ERROR; |
| 3068 if (plural && pluralCount != NULL) { |
| 3069 // plural name is only needed when pluralCount != null, |
| 3070 // which means when formatting currency plural names. |
| 3071 // For other cases, pluralCount == null, |
| 3072 // and plural names are not needed. |
| 3073 int32_t len; |
| 3074 // TODO: num of char in plural count |
| 3075 char pluralCountChar[10]; |
| 3076 if (pluralCount->length() >= 10) { |
| 3077 break; |
| 3078 } |
| 3079 pluralCount->extract(0, pluralCount->length(), pluralCou
ntChar); |
| 3080 UBool isChoiceFormat; |
| 3081 const UChar* s = ucurr_getPluralName(currencyUChars, |
| 3082 fSymbols != NULL ? fSymbols->getLocale().getName() : |
| 3083 Locale::getDefault().getName(), &isChoiceFormat, |
| 3084 pluralCountChar, &len, &ec); |
| 3085 affix += UnicodeString(s, len); |
| 3086 handler.addAttribute(kCurrencyField, beginIdx, affix.len
gth()); |
| 3087 } else if(intl) { |
| 3088 affix += currencyUChars; |
| 3089 handler.addAttribute(kCurrencyField, beginIdx, affix.len
gth()); |
| 3090 } else { |
| 3091 int32_t len; |
| 3092 UBool isChoiceFormat; |
| 3093 // If fSymbols is NULL, use default locale |
| 3094 const UChar* s = ucurr_getName(currencyUChars, |
| 3095 fSymbols != NULL ? fSymbols->getLocale().getName() :
Locale::getDefault().getName(), |
| 3096 UCURR_SYMBOL_NAME, &isChoiceFormat, &len, &ec); |
| 3097 if (isChoiceFormat) { |
| 3098 // Two modes here: If doFormat is false, we set up |
| 3099 // currencyChoice. If doFormat is true, we use the |
| 3100 // previously created currencyChoice to format the |
| 3101 // value in digitList. |
| 3102 if (!doFormat) { |
| 3103 // If the currency is handled by a ChoiceFormat, |
| 3104 // then we're not going to use the expanded |
| 3105 // patterns. Instantiate the ChoiceFormat and |
| 3106 // return. |
| 3107 if (fCurrencyChoice == NULL) { |
| 3108 // TODO Replace double-check with proper thr
ead-safe code |
| 3109 ChoiceFormat* fmt = new ChoiceFormat(s, ec); |
| 3110 if (U_SUCCESS(ec)) { |
| 3111 umtx_lock(NULL); |
| 3112 if (fCurrencyChoice == NULL) { |
| 3113 // Cast away const |
| 3114 ((DecimalFormat*)this)->fCurrencyCho
ice = fmt; |
| 3115 fmt = NULL; |
| 3116 } |
| 3117 umtx_unlock(NULL); |
| 3118 delete fmt; |
| 3119 } |
| 3120 } |
| 3121 // We could almost return null or "" here, since
the |
| 3122 // expanded affixes are almost not used at all |
| 3123 // in this situation. However, one method -- |
| 3124 // toPattern() -- still does use the expanded |
| 3125 // affixes, in order to set up a padding |
| 3126 // pattern. We use the CURRENCY_SIGN as a |
| 3127 // placeholder. |
| 3128 affix.append(kCurrencySign); |
| 3129 } else { |
| 3130 if (fCurrencyChoice != NULL) { |
| 3131 FieldPosition pos(0); // ignored |
| 3132 if (number < 0) { |
| 3133 number = -number; |
| 3134 } |
| 3135 fCurrencyChoice->format(number, affix, pos); |
| 3136 } else { |
| 3137 // We only arrive here if the currency choic
e |
| 3138 // format in the locale data is INVALID. |
| 3139 affix += currencyUChars; |
| 3140 handler.addAttribute(kCurrencyField, beginId
x, affix.length()); |
| 3141 } |
| 3142 } |
| 3143 continue; |
| 3144 } |
| 3145 affix += UnicodeString(s, len); |
| 3146 handler.addAttribute(kCurrencyField, beginIdx, affix.len
gth()); |
| 3147 } |
| 3148 } else { |
| 3149 if(intl) { |
| 3150 affix += getConstSymbol(DecimalFormatSymbols::kIntlCurre
ncySymbol); |
| 3151 } else { |
| 3152 affix += getConstSymbol(DecimalFormatSymbols::kCurrencyS
ymbol); |
| 3153 } |
| 3154 handler.addAttribute(kCurrencyField, beginIdx, affix.length(
)); |
| 3155 } |
| 3156 break; |
| 3157 } |
| 3158 case kPatternPercent: |
| 3159 affix += getConstSymbol(DecimalFormatSymbols::kPercentSymbol); |
| 3160 handler.addAttribute(kPercentField, beginIdx, affix.length()); |
| 3161 break; |
| 3162 case kPatternPerMill: |
| 3163 affix += getConstSymbol(DecimalFormatSymbols::kPerMillSymbol); |
| 3164 handler.addAttribute(kPermillField, beginIdx, affix.length()); |
| 3165 break; |
| 3166 case kPatternPlus: |
| 3167 affix += getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol); |
| 3168 handler.addAttribute(kSignField, beginIdx, affix.length()); |
| 3169 break; |
| 3170 case kPatternMinus: |
| 3171 affix += getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); |
| 3172 handler.addAttribute(kSignField, beginIdx, affix.length()); |
| 3173 break; |
| 3174 default: |
| 3175 affix.append(c); |
| 3176 break; |
| 3177 } |
| 3178 } |
| 3179 else { |
| 3180 affix.append(c); |
| 3181 } |
| 3182 } |
| 3183 } |
| 3184 |
| 3185 /** |
| 3186 * Append an affix to the given StringBuffer. |
| 3187 * @param buf buffer to append to |
| 3188 * @param isNegative |
| 3189 * @param isPrefix |
| 3190 */ |
| 3191 int32_t DecimalFormat::appendAffix(UnicodeString& buf, double number, |
| 3192 FieldPositionHandler& handler, |
| 3193 UBool isNegative, UBool isPrefix) const { |
| 3194 // plural format precedes choice format |
| 3195 if (fCurrencyChoice != 0 && |
| 3196 fCurrencySignCount != fgCurrencySignCountInPluralFormat) { |
| 3197 const UnicodeString* affixPat; |
| 3198 if (isPrefix) { |
| 3199 affixPat = isNegative ? fNegPrefixPattern : fPosPrefixPattern; |
| 3200 } else { |
| 3201 affixPat = isNegative ? fNegSuffixPattern : fPosSuffixPattern; |
| 3202 } |
| 3203 if (affixPat) { |
| 3204 UnicodeString affixBuf; |
| 3205 expandAffix(*affixPat, affixBuf, number, handler, TRUE, NULL); |
| 3206 buf.append(affixBuf); |
| 3207 return affixBuf.length(); |
| 3208 } |
| 3209 // else someone called a function that reset the pattern. |
| 3210 } |
| 3211 |
| 3212 const UnicodeString* affix; |
| 3213 if (fCurrencySignCount == fgCurrencySignCountInPluralFormat) { |
| 3214 UnicodeString pluralCount = fCurrencyPluralInfo->getPluralRules()->selec
t(number); |
| 3215 AffixesForCurrency* oneSet; |
| 3216 if (fStyle == NumberFormat::kPluralCurrencyStyle) { |
| 3217 oneSet = (AffixesForCurrency*)fPluralAffixesForCurrency->get(pluralC
ount); |
| 3218 } else { |
| 3219 oneSet = (AffixesForCurrency*)fAffixesForCurrency->get(pluralCount); |
| 3220 } |
| 3221 if (isPrefix) { |
| 3222 affix = isNegative ? &oneSet->negPrefixForCurrency : |
| 3223 &oneSet->posPrefixForCurrency; |
| 3224 } else { |
| 3225 affix = isNegative ? &oneSet->negSuffixForCurrency : |
| 3226 &oneSet->posSuffixForCurrency; |
| 3227 } |
| 3228 } else { |
| 3229 if (isPrefix) { |
| 3230 affix = isNegative ? &fNegativePrefix : &fPositivePrefix; |
| 3231 } else { |
| 3232 affix = isNegative ? &fNegativeSuffix : &fPositiveSuffix; |
| 3233 } |
| 3234 } |
| 3235 |
| 3236 int32_t begin = (int) buf.length(); |
| 3237 |
| 3238 buf.append(*affix); |
| 3239 |
| 3240 if (handler.isRecording()) { |
| 3241 int32_t offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbol
s::kCurrencySymbol)); |
| 3242 if (offset > -1) { |
| 3243 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kCurrencySymbol
); |
| 3244 handler.addAttribute(kCurrencyField, begin + offset, begin + offset + af
f.length()); |
| 3245 } |
| 3246 |
| 3247 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kIntl
CurrencySymbol)); |
| 3248 if (offset > -1) { |
| 3249 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kIntlCurrencySy
mbol); |
| 3250 handler.addAttribute(kCurrencyField, begin + offset, begin + offset + af
f.length()); |
| 3251 } |
| 3252 |
| 3253 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kMinu
sSignSymbol)); |
| 3254 if (offset > -1) { |
| 3255 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kMinusSignSymbo
l); |
| 3256 handler.addAttribute(kSignField, begin + offset, begin + offset + aff.le
ngth()); |
| 3257 } |
| 3258 |
| 3259 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPerc
entSymbol)); |
| 3260 if (offset > -1) { |
| 3261 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPercentSymbol)
; |
| 3262 handler.addAttribute(kPercentField, begin + offset, begin + offset + aff
.length()); |
| 3263 } |
| 3264 |
| 3265 offset = (int) (*affix).indexOf(getConstSymbol(DecimalFormatSymbols::kPerM
illSymbol)); |
| 3266 if (offset > -1) { |
| 3267 UnicodeString aff = getConstSymbol(DecimalFormatSymbols::kPerMillSymbol)
; |
| 3268 handler.addAttribute(kPermillField, begin + offset, begin + offset + aff
.length()); |
| 3269 } |
| 3270 } |
| 3271 return affix->length(); |
| 3272 } |
| 3273 |
| 3274 /** |
| 3275 * Appends an affix pattern to the given StringBuffer, quoting special |
| 3276 * characters as needed. Uses the internal affix pattern, if that exists, |
| 3277 * or the literal affix, if the internal affix pattern is null. The |
| 3278 * appended string will generate the same affix pattern (or literal affix) |
| 3279 * when passed to toPattern(). |
| 3280 * |
| 3281 * @param appendTo the affix string is appended to this |
| 3282 * @param affixPattern a pattern such as fPosPrefixPattern; may be null |
| 3283 * @param expAffix a corresponding expanded affix, such as fPositivePrefix. |
| 3284 * Ignored unless affixPattern is null. If affixPattern is null, then |
| 3285 * expAffix is appended as a literal affix. |
| 3286 * @param localized true if the appended pattern should contain localized |
| 3287 * pattern characters; otherwise, non-localized pattern chars are appended |
| 3288 */ |
| 3289 void DecimalFormat::appendAffixPattern(UnicodeString& appendTo, |
| 3290 const UnicodeString* affixPattern, |
| 3291 const UnicodeString& expAffix, |
| 3292 UBool localized) const { |
| 3293 if (affixPattern == 0) { |
| 3294 appendAffixPattern(appendTo, expAffix, localized); |
| 3295 } else { |
| 3296 int i; |
| 3297 for (int pos=0; pos<affixPattern->length(); pos=i) { |
| 3298 i = affixPattern->indexOf(kQuote, pos); |
| 3299 if (i < 0) { |
| 3300 UnicodeString s; |
| 3301 affixPattern->extractBetween(pos, affixPattern->length(), s); |
| 3302 appendAffixPattern(appendTo, s, localized); |
| 3303 break; |
| 3304 } |
| 3305 if (i > pos) { |
| 3306 UnicodeString s; |
| 3307 affixPattern->extractBetween(pos, i, s); |
| 3308 appendAffixPattern(appendTo, s, localized); |
| 3309 } |
| 3310 UChar32 c = affixPattern->char32At(++i); |
| 3311 ++i; |
| 3312 if (c == kQuote) { |
| 3313 appendTo.append(c).append(c); |
| 3314 // Fall through and append another kQuote below |
| 3315 } else if (c == kCurrencySign && |
| 3316 i<affixPattern->length() && |
| 3317 affixPattern->char32At(i) == kCurrencySign) { |
| 3318 ++i; |
| 3319 appendTo.append(c).append(c); |
| 3320 } else if (localized) { |
| 3321 switch (c) { |
| 3322 case kPatternPercent: |
| 3323 appendTo += getConstSymbol(DecimalFormatSymbols::kPercentSym
bol); |
| 3324 break; |
| 3325 case kPatternPerMill: |
| 3326 appendTo += getConstSymbol(DecimalFormatSymbols::kPerMillSym
bol); |
| 3327 break; |
| 3328 case kPatternPlus: |
| 3329 appendTo += getConstSymbol(DecimalFormatSymbols::kPlusSignSy
mbol); |
| 3330 break; |
| 3331 case kPatternMinus: |
| 3332 appendTo += getConstSymbol(DecimalFormatSymbols::kMinusSignS
ymbol); |
| 3333 break; |
| 3334 default: |
| 3335 appendTo.append(c); |
| 3336 } |
| 3337 } else { |
| 3338 appendTo.append(c); |
| 3339 } |
| 3340 } |
| 3341 } |
| 3342 } |
| 3343 |
| 3344 /** |
| 3345 * Append an affix to the given StringBuffer, using quotes if |
| 3346 * there are special characters. Single quotes themselves must be |
| 3347 * escaped in either case. |
| 3348 */ |
| 3349 void |
| 3350 DecimalFormat::appendAffixPattern(UnicodeString& appendTo, |
| 3351 const UnicodeString& affix, |
| 3352 UBool localized) const { |
| 3353 UBool needQuote; |
| 3354 if(localized) { |
| 3355 needQuote = affix.indexOf(getConstSymbol(DecimalFormatSymbols::kZeroDigi
tSymbol)) >= 0 |
| 3356 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kGroupingSepar
atorSymbol)) >= 0 |
| 3357 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDecimalSepara
torSymbol)) >= 0 |
| 3358 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPercentSymbol
)) >= 0 |
| 3359 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPerMillSymbol
)) >= 0 |
| 3360 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kDigitSymbol))
>= 0 |
| 3361 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPatternSepara
torSymbol)) >= 0 |
| 3362 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kPlusSignSymbo
l)) >= 0 |
| 3363 || affix.indexOf(getConstSymbol(DecimalFormatSymbols::kMinusSignSymb
ol)) >= 0 |
| 3364 || affix.indexOf(kCurrencySign) >= 0; |
| 3365 } |
| 3366 else { |
| 3367 needQuote = affix.indexOf(kPatternZeroDigit) >= 0 |
| 3368 || affix.indexOf(kPatternGroupingSeparator) >= 0 |
| 3369 || affix.indexOf(kPatternDecimalSeparator) >= 0 |
| 3370 || affix.indexOf(kPatternPercent) >= 0 |
| 3371 || affix.indexOf(kPatternPerMill) >= 0 |
| 3372 || affix.indexOf(kPatternDigit) >= 0 |
| 3373 || affix.indexOf(kPatternSeparator) >= 0 |
| 3374 || affix.indexOf(kPatternExponent) >= 0 |
| 3375 || affix.indexOf(kPatternPlus) >= 0 |
| 3376 || affix.indexOf(kPatternMinus) >= 0 |
| 3377 || affix.indexOf(kCurrencySign) >= 0; |
| 3378 } |
| 3379 if (needQuote) |
| 3380 appendTo += (UChar)0x0027 /*'\''*/; |
| 3381 if (affix.indexOf((UChar)0x0027 /*'\''*/) < 0) |
| 3382 appendTo += affix; |
| 3383 else { |
| 3384 for (int32_t j = 0; j < affix.length(); ) { |
| 3385 UChar32 c = affix.char32At(j); |
| 3386 j += U16_LENGTH(c); |
| 3387 appendTo += c; |
| 3388 if (c == 0x0027 /*'\''*/) |
| 3389 appendTo += c; |
| 3390 } |
| 3391 } |
| 3392 if (needQuote) |
| 3393 appendTo += (UChar)0x0027 /*'\''*/; |
| 3394 } |
| 3395 |
| 3396 //------------------------------------------------------------------------------ |
| 3397 |
| 3398 UnicodeString& |
| 3399 DecimalFormat::toPattern(UnicodeString& result, UBool localized) const |
| 3400 { |
| 3401 if (fStyle == NumberFormat::kPluralCurrencyStyle) { |
| 3402 // the prefix or suffix pattern might not be defined yet, |
| 3403 // so they can not be synthesized, |
| 3404 // instead, get them directly. |
| 3405 // but it might not be the actual pattern used in formatting. |
| 3406 // the actual pattern used in formatting depends on the |
| 3407 // formatted number's plural count. |
| 3408 result = fFormatPattern; |
| 3409 return result; |
| 3410 } |
| 3411 result.remove(); |
| 3412 UChar32 zero, sigDigit = kPatternSignificantDigit; |
| 3413 UnicodeString digit, group; |
| 3414 int32_t i; |
| 3415 int32_t roundingDecimalPos = 0; // Pos of decimal in roundingDigits |
| 3416 UnicodeString roundingDigits; |
| 3417 int32_t padPos = (fFormatWidth > 0) ? fPadPosition : -1; |
| 3418 UnicodeString padSpec; |
| 3419 UBool useSigDig = areSignificantDigitsUsed(); |
| 3420 |
| 3421 if (localized) { |
| 3422 digit.append(getConstSymbol(DecimalFormatSymbols::kDigitSymbol)); |
| 3423 group.append(getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymb
ol)); |
| 3424 zero = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0
); |
| 3425 if (useSigDig) { |
| 3426 sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSym
bol).char32At(0); |
| 3427 } |
| 3428 } |
| 3429 else { |
| 3430 digit.append((UChar)kPatternDigit); |
| 3431 group.append((UChar)kPatternGroupingSeparator); |
| 3432 zero = (UChar32)kPatternZeroDigit; |
| 3433 } |
| 3434 if (fFormatWidth > 0) { |
| 3435 if (localized) { |
| 3436 padSpec.append(getConstSymbol(DecimalFormatSymbols::kPadEscapeSymbol
)); |
| 3437 } |
| 3438 else { |
| 3439 padSpec.append((UChar)kPatternPadEscape); |
| 3440 } |
| 3441 padSpec.append(fPad); |
| 3442 } |
| 3443 if (fRoundingIncrement != NULL) { |
| 3444 for(i=0; i<fRoundingIncrement->getCount(); ++i) { |
| 3445 roundingDigits.append(zero+(fRoundingIncrement->getDigitValue(i))); //
Convert to Unicode digit |
| 3446 } |
| 3447 roundingDecimalPos = fRoundingIncrement->getDecimalAt(); |
| 3448 } |
| 3449 for (int32_t part=0; part<2; ++part) { |
| 3450 if (padPos == kPadBeforePrefix) { |
| 3451 result.append(padSpec); |
| 3452 } |
| 3453 appendAffixPattern(result, |
| 3454 (part==0 ? fPosPrefixPattern : fNegPrefixPattern), |
| 3455 (part==0 ? fPositivePrefix : fNegativePrefix), |
| 3456 localized); |
| 3457 if (padPos == kPadAfterPrefix && ! padSpec.isEmpty()) { |
| 3458 result.append(padSpec); |
| 3459 } |
| 3460 int32_t sub0Start = result.length(); |
| 3461 int32_t g = isGroupingUsed() ? _max(0, fGroupingSize) : 0; |
| 3462 if (g > 0 && fGroupingSize2 > 0 && fGroupingSize2 != fGroupingSize) { |
| 3463 g += fGroupingSize2; |
| 3464 } |
| 3465 int32_t maxDig = 0, minDig = 0, maxSigDig = 0; |
| 3466 if (useSigDig) { |
| 3467 minDig = getMinimumSignificantDigits(); |
| 3468 maxDig = maxSigDig = getMaximumSignificantDigits(); |
| 3469 } else { |
| 3470 minDig = getMinimumIntegerDigits(); |
| 3471 maxDig = getMaximumIntegerDigits(); |
| 3472 } |
| 3473 if (fUseExponentialNotation) { |
| 3474 if (maxDig > kMaxScientificIntegerDigits) { |
| 3475 maxDig = 1; |
| 3476 } |
| 3477 } else if (useSigDig) { |
| 3478 maxDig = _max(maxDig, g+1); |
| 3479 } else { |
| 3480 maxDig = _max(_max(g, getMinimumIntegerDigits()), |
| 3481 roundingDecimalPos) + 1; |
| 3482 } |
| 3483 for (i = maxDig; i > 0; --i) { |
| 3484 if (!fUseExponentialNotation && i<maxDig && |
| 3485 isGroupingPosition(i)) { |
| 3486 result.append(group); |
| 3487 } |
| 3488 if (useSigDig) { |
| 3489 // #@,@### (maxSigDig == 5, minSigDig == 2) |
| 3490 // 65 4321 (1-based pos, count from the right) |
| 3491 // Use # if pos > maxSigDig or 1 <= pos <= (maxSigDig - minSigDi
g) |
| 3492 // Use @ if (maxSigDig - minSigDig) < pos <= maxSigDig |
| 3493 if (maxSigDig >= i && i > (maxSigDig - minDig)) { |
| 3494 result.append(sigDigit); |
| 3495 } else { |
| 3496 result.append(digit); |
| 3497 } |
| 3498 } else { |
| 3499 if (! roundingDigits.isEmpty()) { |
| 3500 int32_t pos = roundingDecimalPos - i; |
| 3501 if (pos >= 0 && pos < roundingDigits.length()) { |
| 3502 result.append((UChar) (roundingDigits.char32At(pos) - kP
atternZeroDigit + zero)); |
| 3503 continue; |
| 3504 } |
| 3505 } |
| 3506 if (i<=minDig) { |
| 3507 result.append(zero); |
| 3508 } else { |
| 3509 result.append(digit); |
| 3510 } |
| 3511 } |
| 3512 } |
| 3513 if (!useSigDig) { |
| 3514 if (getMaximumFractionDigits() > 0 || fDecimalSeparatorAlwaysShown)
{ |
| 3515 if (localized) { |
| 3516 result += getConstSymbol(DecimalFormatSymbols::kDecimalSepar
atorSymbol); |
| 3517 } |
| 3518 else { |
| 3519 result.append((UChar)kPatternDecimalSeparator); |
| 3520 } |
| 3521 } |
| 3522 int32_t pos = roundingDecimalPos; |
| 3523 for (i = 0; i < getMaximumFractionDigits(); ++i) { |
| 3524 if (! roundingDigits.isEmpty() && pos < roundingDigits.length())
{ |
| 3525 if (pos < 0) { |
| 3526 result.append(zero); |
| 3527 } |
| 3528 else { |
| 3529 result.append((UChar)(roundingDigits.char32At(pos) - kPa
tternZeroDigit + zero)); |
| 3530 } |
| 3531 ++pos; |
| 3532 continue; |
| 3533 } |
| 3534 if (i<getMinimumFractionDigits()) { |
| 3535 result.append(zero); |
| 3536 } |
| 3537 else { |
| 3538 result.append(digit); |
| 3539 } |
| 3540 } |
| 3541 } |
| 3542 if (fUseExponentialNotation) { |
| 3543 if (localized) { |
| 3544 result += getConstSymbol(DecimalFormatSymbols::kExponentialSymbo
l); |
| 3545 } |
| 3546 else { |
| 3547 result.append((UChar)kPatternExponent); |
| 3548 } |
| 3549 if (fExponentSignAlwaysShown) { |
| 3550 if (localized) { |
| 3551 result += getConstSymbol(DecimalFormatSymbols::kPlusSignSymb
ol); |
| 3552 } |
| 3553 else { |
| 3554 result.append((UChar)kPatternPlus); |
| 3555 } |
| 3556 } |
| 3557 for (i=0; i<fMinExponentDigits; ++i) { |
| 3558 result.append(zero); |
| 3559 } |
| 3560 } |
| 3561 if (! padSpec.isEmpty() && !fUseExponentialNotation) { |
| 3562 int32_t add = fFormatWidth - result.length() + sub0Start |
| 3563 - ((part == 0) |
| 3564 ? fPositivePrefix.length() + fPositiveSuffix.length() |
| 3565 : fNegativePrefix.length() + fNegativeSuffix.length()); |
| 3566 while (add > 0) { |
| 3567 result.insert(sub0Start, digit); |
| 3568 ++maxDig; |
| 3569 --add; |
| 3570 // Only add a grouping separator if we have at least |
| 3571 // 2 additional characters to be added, so we don't |
| 3572 // end up with ",###". |
| 3573 if (add>1 && isGroupingPosition(maxDig)) { |
| 3574 result.insert(sub0Start, group); |
| 3575 --add; |
| 3576 } |
| 3577 } |
| 3578 } |
| 3579 if (fPadPosition == kPadBeforeSuffix && ! padSpec.isEmpty()) { |
| 3580 result.append(padSpec); |
| 3581 } |
| 3582 if (part == 0) { |
| 3583 appendAffixPattern(result, fPosSuffixPattern, fPositiveSuffix, local
ized); |
| 3584 if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) { |
| 3585 result.append(padSpec); |
| 3586 } |
| 3587 UBool isDefault = FALSE; |
| 3588 if ((fNegSuffixPattern == fPosSuffixPattern && // both null |
| 3589 fNegativeSuffix == fPositiveSuffix) |
| 3590 || (fNegSuffixPattern != 0 && fPosSuffixPattern != 0 && |
| 3591 *fNegSuffixPattern == *fPosSuffixPattern)) |
| 3592 { |
| 3593 if (fNegPrefixPattern != NULL && fPosPrefixPattern != NULL) |
| 3594 { |
| 3595 int32_t length = fPosPrefixPattern->length(); |
| 3596 isDefault = fNegPrefixPattern->length() == (length+2) && |
| 3597 (*fNegPrefixPattern)[(int32_t)0] == kQuote && |
| 3598 (*fNegPrefixPattern)[(int32_t)1] == kPatternMinus && |
| 3599 fNegPrefixPattern->compare(2, length, *fPosPrefixPattern
, 0, length) == 0; |
| 3600 } |
| 3601 if (!isDefault && |
| 3602 fNegPrefixPattern == NULL && fPosPrefixPattern == NULL) |
| 3603 { |
| 3604 int32_t length = fPositivePrefix.length(); |
| 3605 isDefault = fNegativePrefix.length() == (length+1) && |
| 3606 fNegativePrefix.compare(getConstSymbol(DecimalFormatSymb
ols::kMinusSignSymbol)) == 0 && |
| 3607 fNegativePrefix.compare(1, length, fPositivePrefix, 0, l
ength) == 0; |
| 3608 } |
| 3609 } |
| 3610 if (isDefault) { |
| 3611 break; // Don't output default negative subpattern |
| 3612 } else { |
| 3613 if (localized) { |
| 3614 result += getConstSymbol(DecimalFormatSymbols::kPatternSepar
atorSymbol); |
| 3615 } |
| 3616 else { |
| 3617 result.append((UChar)kPatternSeparator); |
| 3618 } |
| 3619 } |
| 3620 } else { |
| 3621 appendAffixPattern(result, fNegSuffixPattern, fNegativeSuffix, local
ized); |
| 3622 if (fPadPosition == kPadAfterSuffix && ! padSpec.isEmpty()) { |
| 3623 result.append(padSpec); |
| 3624 } |
| 3625 } |
| 3626 } |
| 3627 |
| 3628 return result; |
| 3629 } |
| 3630 |
| 3631 //------------------------------------------------------------------------------ |
| 3632 |
| 3633 void |
| 3634 DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) |
| 3635 { |
| 3636 UParseError parseError; |
| 3637 applyPattern(pattern, FALSE, parseError, status); |
| 3638 } |
| 3639 |
| 3640 //------------------------------------------------------------------------------ |
| 3641 |
| 3642 void |
| 3643 DecimalFormat::applyPattern(const UnicodeString& pattern, |
| 3644 UParseError& parseError, |
| 3645 UErrorCode& status) |
| 3646 { |
| 3647 applyPattern(pattern, FALSE, parseError, status); |
| 3648 } |
| 3649 //------------------------------------------------------------------------------ |
| 3650 |
| 3651 void |
| 3652 DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& s
tatus) |
| 3653 { |
| 3654 UParseError parseError; |
| 3655 applyPattern(pattern, TRUE,parseError,status); |
| 3656 } |
| 3657 |
| 3658 //------------------------------------------------------------------------------ |
| 3659 |
| 3660 void |
| 3661 DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, |
| 3662 UParseError& parseError, |
| 3663 UErrorCode& status) |
| 3664 { |
| 3665 applyPattern(pattern, TRUE,parseError,status); |
| 3666 } |
| 3667 |
| 3668 //------------------------------------------------------------------------------ |
| 3669 |
| 3670 void |
| 3671 DecimalFormat::applyPatternWithoutExpandAffix(const UnicodeString& pattern, |
| 3672 UBool localized, |
| 3673 UParseError& parseError, |
| 3674 UErrorCode& status) |
| 3675 { |
| 3676 if (U_FAILURE(status)) |
| 3677 { |
| 3678 return; |
| 3679 } |
| 3680 // Clear error struct |
| 3681 parseError.offset = -1; |
| 3682 parseError.preContext[0] = parseError.postContext[0] = (UChar)0; |
| 3683 |
| 3684 // Set the significant pattern symbols |
| 3685 UChar32 zeroDigit = kPatternZeroDigit; // '0' |
| 3686 UChar32 sigDigit = kPatternSignificantDigit; // '@' |
| 3687 UnicodeString groupingSeparator ((UChar)kPatternGroupingSeparator); |
| 3688 UnicodeString decimalSeparator ((UChar)kPatternDecimalSeparator); |
| 3689 UnicodeString percent ((UChar)kPatternPercent); |
| 3690 UnicodeString perMill ((UChar)kPatternPerMill); |
| 3691 UnicodeString digit ((UChar)kPatternDigit); // '#' |
| 3692 UnicodeString separator ((UChar)kPatternSeparator); |
| 3693 UnicodeString exponent ((UChar)kPatternExponent); |
| 3694 UnicodeString plus ((UChar)kPatternPlus); |
| 3695 UnicodeString minus ((UChar)kPatternMinus); |
| 3696 UnicodeString padEscape ((UChar)kPatternPadEscape); |
| 3697 // Substitute with the localized symbols if necessary |
| 3698 if (localized) { |
| 3699 zeroDigit = getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char3
2At(0); |
| 3700 sigDigit = getConstSymbol(DecimalFormatSymbols::kSignificantDigitSymbol)
.char32At(0); |
| 3701 groupingSeparator. remove().append(getConstSymbol(DecimalFormatSymbols:
:kGroupingSeparatorSymbol)); |
| 3702 decimalSeparator. remove().append(getConstSymbol(DecimalFormatSymbols:
:kDecimalSeparatorSymbol)); |
| 3703 percent. remove().append(getConstSymbol(DecimalFormatSymbols:
:kPercentSymbol)); |
| 3704 perMill. remove().append(getConstSymbol(DecimalFormatSymbols:
:kPerMillSymbol)); |
| 3705 digit. remove().append(getConstSymbol(DecimalFormatSymbols:
:kDigitSymbol)); |
| 3706 separator. remove().append(getConstSymbol(DecimalFormatSymbols:
:kPatternSeparatorSymbol)); |
| 3707 exponent. remove().append(getConstSymbol(DecimalFormatSymbols:
:kExponentialSymbol)); |
| 3708 plus. remove().append(getConstSymbol(DecimalFormatSymbols:
:kPlusSignSymbol)); |
| 3709 minus. remove().append(getConstSymbol(DecimalFormatSymbols:
:kMinusSignSymbol)); |
| 3710 padEscape. remove().append(getConstSymbol(DecimalFormatSymbols:
:kPadEscapeSymbol)); |
| 3711 } |
| 3712 UChar nineDigit = (UChar)(zeroDigit + 9); |
| 3713 int32_t digitLen = digit.length(); |
| 3714 int32_t groupSepLen = groupingSeparator.length(); |
| 3715 int32_t decimalSepLen = decimalSeparator.length(); |
| 3716 |
| 3717 int32_t pos = 0; |
| 3718 int32_t patLen = pattern.length(); |
| 3719 // Part 0 is the positive pattern. Part 1, if present, is the negative |
| 3720 // pattern. |
| 3721 for (int32_t part=0; part<2 && pos<patLen; ++part) { |
| 3722 // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix, |
| 3723 // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is |
| 3724 // between the prefix and suffix, and consists of pattern |
| 3725 // characters. In the prefix and suffix, percent, perMill, and |
| 3726 // currency symbols are recognized and translated. |
| 3727 int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0; |
| 3728 |
| 3729 // It's important that we don't change any fields of this object |
| 3730 // prematurely. We set the following variables for the multiplier, |
| 3731 // grouping, etc., and then only change the actual object fields if |
| 3732 // everything parses correctly. This also lets us register |
| 3733 // the data from part 0 and ignore the part 1, except for the |
| 3734 // prefix and suffix. |
| 3735 UnicodeString prefix; |
| 3736 UnicodeString suffix; |
| 3737 int32_t decimalPos = -1; |
| 3738 int32_t multiplier = 1; |
| 3739 int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0, sig
DigitCount = 0; |
| 3740 int8_t groupingCount = -1; |
| 3741 int8_t groupingCount2 = -1; |
| 3742 int32_t padPos = -1; |
| 3743 UChar32 padChar = 0; |
| 3744 int32_t roundingPos = -1; |
| 3745 DigitList roundingInc; |
| 3746 int8_t expDigits = -1; |
| 3747 UBool expSignAlways = FALSE; |
| 3748 |
| 3749 // The affix is either the prefix or the suffix. |
| 3750 UnicodeString* affix = &prefix; |
| 3751 |
| 3752 int32_t start = pos; |
| 3753 UBool isPartDone = FALSE; |
| 3754 UChar32 ch; |
| 3755 |
| 3756 for (; !isPartDone && pos < patLen; ) { |
| 3757 // Todo: account for surrogate pairs |
| 3758 ch = pattern.char32At(pos); |
| 3759 switch (subpart) { |
| 3760 case 0: // Pattern proper subpart (between prefix & suffix) |
| 3761 // Process the digits, decimal, and grouping characters. We |
| 3762 // record five pieces of information. We expect the digits |
| 3763 // to occur in the pattern ####00.00####, and we record the |
| 3764 // number of left digits, zero (central) digits, and right |
| 3765 // digits. The position of the last grouping character is |
| 3766 // recorded (should be somewhere within the first two blocks |
| 3767 // of characters), as is the position of the decimal point, |
| 3768 // if any (should be in the zero digits). If there is no |
| 3769 // decimal point, then there should be no right digits. |
| 3770 if (pattern.compare(pos, digitLen, digit) == 0) { |
| 3771 if (zeroDigitCount > 0 || sigDigitCount > 0) { |
| 3772 ++digitRightCount; |
| 3773 } else { |
| 3774 ++digitLeftCount; |
| 3775 } |
| 3776 if (groupingCount >= 0 && decimalPos < 0) { |
| 3777 ++groupingCount; |
| 3778 } |
| 3779 pos += digitLen; |
| 3780 } else if ((ch >= zeroDigit && ch <= nineDigit) || |
| 3781 ch == sigDigit) { |
| 3782 if (digitRightCount > 0) { |
| 3783 // Unexpected '0' |
| 3784 debug("Unexpected '0'") |
| 3785 status = U_UNEXPECTED_TOKEN; |
| 3786 syntaxError(pattern,pos,parseError); |
| 3787 return; |
| 3788 } |
| 3789 if (ch == sigDigit) { |
| 3790 ++sigDigitCount; |
| 3791 } else { |
| 3792 ++zeroDigitCount; |
| 3793 if (ch != zeroDigit && roundingPos < 0) { |
| 3794 roundingPos = digitLeftCount + zeroDigitCount; |
| 3795 } |
| 3796 if (roundingPos >= 0) { |
| 3797 roundingInc.append((char)(ch - zeroDigit + '0')); |
| 3798 } |
| 3799 } |
| 3800 if (groupingCount >= 0 && decimalPos < 0) { |
| 3801 ++groupingCount; |
| 3802 } |
| 3803 pos += U16_LENGTH(ch); |
| 3804 } else if (pattern.compare(pos, groupSepLen, groupingSeparator)
== 0) { |
| 3805 if (decimalPos >= 0) { |
| 3806 // Grouping separator after decimal |
| 3807 debug("Grouping separator after decimal") |
| 3808 status = U_UNEXPECTED_TOKEN; |
| 3809 syntaxError(pattern,pos,parseError); |
| 3810 return; |
| 3811 } |
| 3812 groupingCount2 = groupingCount; |
| 3813 groupingCount = 0; |
| 3814 pos += groupSepLen; |
| 3815 } else if (pattern.compare(pos, decimalSepLen, decimalSeparator)
== 0) { |
| 3816 if (decimalPos >= 0) { |
| 3817 // Multiple decimal separators |
| 3818 debug("Multiple decimal separators") |
| 3819 status = U_MULTIPLE_DECIMAL_SEPARATORS; |
| 3820 syntaxError(pattern,pos,parseError); |
| 3821 return; |
| 3822 } |
| 3823 // Intentionally incorporate the digitRightCount, |
| 3824 // even though it is illegal for this to be > 0 |
| 3825 // at this point. We check pattern syntax below. |
| 3826 decimalPos = digitLeftCount + zeroDigitCount + digitRightCou
nt; |
| 3827 pos += decimalSepLen; |
| 3828 } else { |
| 3829 if (pattern.compare(pos, exponent.length(), exponent) == 0)
{ |
| 3830 if (expDigits >= 0) { |
| 3831 // Multiple exponential symbols |
| 3832 debug("Multiple exponential symbols") |
| 3833 status = U_MULTIPLE_EXPONENTIAL_SYMBOLS; |
| 3834 syntaxError(pattern,pos,parseError); |
| 3835 return; |
| 3836 } |
| 3837 if (groupingCount >= 0) { |
| 3838 // Grouping separator in exponential pattern |
| 3839 debug("Grouping separator in exponential pattern") |
| 3840 status = U_MALFORMED_EXPONENTIAL_PATTERN; |
| 3841 syntaxError(pattern,pos,parseError); |
| 3842 return; |
| 3843 } |
| 3844 pos += exponent.length(); |
| 3845 // Check for positive prefix |
| 3846 if (pos < patLen |
| 3847 && pattern.compare(pos, plus.length(), plus) == 0) { |
| 3848 expSignAlways = TRUE; |
| 3849 pos += plus.length(); |
| 3850 } |
| 3851 // Use lookahead to parse out the exponential part of th
e |
| 3852 // pattern, then jump into suffix subpart. |
| 3853 expDigits = 0; |
| 3854 while (pos < patLen && |
| 3855 pattern.char32At(pos) == zeroDigit) { |
| 3856 ++expDigits; |
| 3857 pos += U16_LENGTH(zeroDigit); |
| 3858 } |
| 3859 |
| 3860 // 1. Require at least one mantissa pattern digit |
| 3861 // 2. Disallow "#+ @" in mantissa |
| 3862 // 3. Require at least one exponent pattern digit |
| 3863 if (((digitLeftCount + zeroDigitCount) < 1 && |
| 3864 (sigDigitCount + digitRightCount) < 1) || |
| 3865 (sigDigitCount > 0 && digitLeftCount > 0) || |
| 3866 expDigits < 1) { |
| 3867 // Malformed exponential pattern |
| 3868 debug("Malformed exponential pattern") |
| 3869 status = U_MALFORMED_EXPONENTIAL_PATTERN; |
| 3870 syntaxError(pattern,pos,parseError); |
| 3871 return; |
| 3872 } |
| 3873 } |
| 3874 // Transition to suffix subpart |
| 3875 subpart = 2; // suffix subpart |
| 3876 affix = &suffix; |
| 3877 sub0Limit = pos; |
| 3878 continue; |
| 3879 } |
| 3880 break; |
| 3881 case 1: // Prefix subpart |
| 3882 case 2: // Suffix subpart |
| 3883 // Process the prefix / suffix characters |
| 3884 // Process unquoted characters seen in prefix or suffix |
| 3885 // subpart. |
| 3886 |
| 3887 // Several syntax characters implicitly begins the |
| 3888 // next subpart if we are in the prefix; otherwise |
| 3889 // they are illegal if unquoted. |
| 3890 if (!pattern.compare(pos, digitLen, digit) || |
| 3891 !pattern.compare(pos, groupSepLen, groupingSeparator) || |
| 3892 !pattern.compare(pos, decimalSepLen, decimalSeparator) || |
| 3893 (ch >= zeroDigit && ch <= nineDigit) || |
| 3894 ch == sigDigit) { |
| 3895 if (subpart == 1) { // prefix subpart |
| 3896 subpart = 0; // pattern proper subpart |
| 3897 sub0Start = pos; // Reprocess this character |
| 3898 continue; |
| 3899 } else { |
| 3900 status = U_UNQUOTED_SPECIAL; |
| 3901 syntaxError(pattern,pos,parseError); |
| 3902 return; |
| 3903 } |
| 3904 } else if (ch == kCurrencySign) { |
| 3905 affix->append(kQuote); // Encode currency |
| 3906 // Use lookahead to determine if the currency sign is |
| 3907 // doubled or not. |
| 3908 U_ASSERT(U16_LENGTH(kCurrencySign) == 1); |
| 3909 if ((pos+1) < pattern.length() && pattern[pos+1] == kCurrenc
ySign) { |
| 3910 affix->append(kCurrencySign); |
| 3911 ++pos; // Skip over the doubled character |
| 3912 if ((pos+1) < pattern.length() && |
| 3913 pattern[pos+1] == kCurrencySign) { |
| 3914 affix->append(kCurrencySign); |
| 3915 ++pos; // Skip over the doubled character |
| 3916 fCurrencySignCount = fgCurrencySignCountInPluralForm
at; |
| 3917 } else { |
| 3918 fCurrencySignCount = fgCurrencySignCountInISOFormat; |
| 3919 } |
| 3920 } else { |
| 3921 fCurrencySignCount = fgCurrencySignCountInSymbolFormat; |
| 3922 } |
| 3923 // Fall through to append(ch) |
| 3924 } else if (ch == kQuote) { |
| 3925 // A quote outside quotes indicates either the opening |
| 3926 // quote or two quotes, which is a quote literal. That is, |
| 3927 // we have the first quote in 'do' or o''clock. |
| 3928 U_ASSERT(U16_LENGTH(kQuote) == 1); |
| 3929 ++pos; |
| 3930 if (pos < pattern.length() && pattern[pos] == kQuote) { |
| 3931 affix->append(kQuote); // Encode quote |
| 3932 // Fall through to append(ch) |
| 3933 } else { |
| 3934 subpart += 2; // open quote |
| 3935 continue; |
| 3936 } |
| 3937 } else if (pattern.compare(pos, separator.length(), separator) =
= 0) { |
| 3938 // Don't allow separators in the prefix, and don't allow |
| 3939 // separators in the second pattern (part == 1). |
| 3940 if (subpart == 1 || part == 1) { |
| 3941 // Unexpected separator |
| 3942 debug("Unexpected separator") |
| 3943 status = U_UNEXPECTED_TOKEN; |
| 3944 syntaxError(pattern,pos,parseError); |
| 3945 return; |
| 3946 } |
| 3947 sub2Limit = pos; |
| 3948 isPartDone = TRUE; // Go to next part |
| 3949 pos += separator.length(); |
| 3950 break; |
| 3951 } else if (pattern.compare(pos, percent.length(), percent) == 0)
{ |
| 3952 // Next handle characters which are appended directly. |
| 3953 if (multiplier != 1) { |
| 3954 // Too many percent/perMill characters |
| 3955 debug("Too many percent characters") |
| 3956 status = U_MULTIPLE_PERCENT_SYMBOLS; |
| 3957 syntaxError(pattern,pos,parseError); |
| 3958 return; |
| 3959 } |
| 3960 affix->append(kQuote); // Encode percent/perMill |
| 3961 affix->append(kPatternPercent); // Use unlocalized pattern c
har |
| 3962 multiplier = 100; |
| 3963 pos += percent.length(); |
| 3964 break; |
| 3965 } else if (pattern.compare(pos, perMill.length(), perMill) == 0)
{ |
| 3966 // Next handle characters which are appended directly. |
| 3967 if (multiplier != 1) { |
| 3968 // Too many percent/perMill characters |
| 3969 debug("Too many perMill characters") |
| 3970 status = U_MULTIPLE_PERMILL_SYMBOLS; |
| 3971 syntaxError(pattern,pos,parseError); |
| 3972 return; |
| 3973 } |
| 3974 affix->append(kQuote); // Encode percent/perMill |
| 3975 affix->append(kPatternPerMill); // Use unlocalized pattern c
har |
| 3976 multiplier = 1000; |
| 3977 pos += perMill.length(); |
| 3978 break; |
| 3979 } else if (pattern.compare(pos, padEscape.length(), padEscape) =
= 0) { |
| 3980 if (padPos >= 0 || // Multiple pad specifiers |
| 3981 (pos+1) == pattern.length()) { // Nothing after padEscap
e |
| 3982 debug("Multiple pad specifiers") |
| 3983 status = U_MULTIPLE_PAD_SPECIFIERS; |
| 3984 syntaxError(pattern,pos,parseError); |
| 3985 return; |
| 3986 } |
| 3987 padPos = pos; |
| 3988 pos += padEscape.length(); |
| 3989 padChar = pattern.char32At(pos); |
| 3990 pos += U16_LENGTH(padChar); |
| 3991 break; |
| 3992 } else if (pattern.compare(pos, minus.length(), minus) == 0) { |
| 3993 affix->append(kQuote); // Encode minus |
| 3994 affix->append(kPatternMinus); |
| 3995 pos += minus.length(); |
| 3996 break; |
| 3997 } else if (pattern.compare(pos, plus.length(), plus) == 0) { |
| 3998 affix->append(kQuote); // Encode plus |
| 3999 affix->append(kPatternPlus); |
| 4000 pos += plus.length(); |
| 4001 break; |
| 4002 } |
| 4003 // Unquoted, non-special characters fall through to here, as |
| 4004 // well as other code which needs to append something to the |
| 4005 // affix. |
| 4006 affix->append(ch); |
| 4007 pos += U16_LENGTH(ch); |
| 4008 break; |
| 4009 case 3: // Prefix subpart, in quote |
| 4010 case 4: // Suffix subpart, in quote |
| 4011 // A quote within quotes indicates either the closing |
| 4012 // quote or two quotes, which is a quote literal. That is, |
| 4013 // we have the second quote in 'do' or 'don''t'. |
| 4014 if (ch == kQuote) { |
| 4015 ++pos; |
| 4016 if (pos < pattern.length() && pattern[pos] == kQuote) { |
| 4017 affix->append(kQuote); // Encode quote |
| 4018 // Fall through to append(ch) |
| 4019 } else { |
| 4020 subpart -= 2; // close quote |
| 4021 continue; |
| 4022 } |
| 4023 } |
| 4024 affix->append(ch); |
| 4025 pos += U16_LENGTH(ch); |
| 4026 break; |
| 4027 } |
| 4028 } |
| 4029 |
| 4030 if (sub0Limit == 0) { |
| 4031 sub0Limit = pattern.length(); |
| 4032 } |
| 4033 |
| 4034 if (sub2Limit == 0) { |
| 4035 sub2Limit = pattern.length(); |
| 4036 } |
| 4037 |
| 4038 /* Handle patterns with no '0' pattern character. These patterns |
| 4039 * are legal, but must be recodified to make sense. "##.###" -> |
| 4040 * "#0.###". ".###" -> ".0##". |
| 4041 * |
| 4042 * We allow patterns of the form "####" to produce a zeroDigitCount |
| 4043 * of zero (got that?); although this seems like it might make it |
| 4044 * possible for format() to produce empty strings, format() checks |
| 4045 * for this condition and outputs a zero digit in this situation. |
| 4046 * Having a zeroDigitCount of zero yields a minimum integer digits |
| 4047 * of zero, which allows proper round-trip patterns. We don't want |
| 4048 * "#" to become "#0" when toPattern() is called (even though that's |
| 4049 * what it really is, semantically). |
| 4050 */ |
| 4051 if (zeroDigitCount == 0 && sigDigitCount == 0 && |
| 4052 digitLeftCount > 0 && decimalPos >= 0) { |
| 4053 // Handle "###.###" and "###." and ".###" |
| 4054 int n = decimalPos; |
| 4055 if (n == 0) |
| 4056 ++n; // Handle ".###" |
| 4057 digitRightCount = digitLeftCount - n; |
| 4058 digitLeftCount = n - 1; |
| 4059 zeroDigitCount = 1; |
| 4060 } |
| 4061 |
| 4062 // Do syntax checking on the digits, decimal points, and quotes. |
| 4063 if ((decimalPos < 0 && digitRightCount > 0 && sigDigitCount == 0) || |
| 4064 (decimalPos >= 0 && |
| 4065 (sigDigitCount > 0 || |
| 4066 decimalPos < digitLeftCount || |
| 4067 decimalPos > (digitLeftCount + zeroDigitCount))) || |
| 4068 groupingCount == 0 || groupingCount2 == 0 || |
| 4069 (sigDigitCount > 0 && zeroDigitCount > 0) || |
| 4070 subpart > 2) |
| 4071 { // subpart > 2 == unmatched quote |
| 4072 debug("Syntax error") |
| 4073 status = U_PATTERN_SYNTAX_ERROR; |
| 4074 syntaxError(pattern,pos,parseError); |
| 4075 return; |
| 4076 } |
| 4077 |
| 4078 // Make sure pad is at legal position before or after affix. |
| 4079 if (padPos >= 0) { |
| 4080 if (padPos == start) { |
| 4081 padPos = kPadBeforePrefix; |
| 4082 } else if (padPos+2 == sub0Start) { |
| 4083 padPos = kPadAfterPrefix; |
| 4084 } else if (padPos == sub0Limit) { |
| 4085 padPos = kPadBeforeSuffix; |
| 4086 } else if (padPos+2 == sub2Limit) { |
| 4087 padPos = kPadAfterSuffix; |
| 4088 } else { |
| 4089 // Illegal pad position |
| 4090 debug("Illegal pad position") |
| 4091 status = U_ILLEGAL_PAD_POSITION; |
| 4092 syntaxError(pattern,pos,parseError); |
| 4093 return; |
| 4094 } |
| 4095 } |
| 4096 |
| 4097 if (part == 0) { |
| 4098 delete fPosPrefixPattern; |
| 4099 delete fPosSuffixPattern; |
| 4100 delete fNegPrefixPattern; |
| 4101 delete fNegSuffixPattern; |
| 4102 fPosPrefixPattern = new UnicodeString(prefix); |
| 4103 /* test for NULL */ |
| 4104 if (fPosPrefixPattern == 0) { |
| 4105 status = U_MEMORY_ALLOCATION_ERROR; |
| 4106 return; |
| 4107 } |
| 4108 fPosSuffixPattern = new UnicodeString(suffix); |
| 4109 /* test for NULL */ |
| 4110 if (fPosSuffixPattern == 0) { |
| 4111 status = U_MEMORY_ALLOCATION_ERROR; |
| 4112 delete fPosPrefixPattern; |
| 4113 return; |
| 4114 } |
| 4115 fNegPrefixPattern = 0; |
| 4116 fNegSuffixPattern = 0; |
| 4117 |
| 4118 fUseExponentialNotation = (expDigits >= 0); |
| 4119 if (fUseExponentialNotation) { |
| 4120 fMinExponentDigits = expDigits; |
| 4121 } |
| 4122 fExponentSignAlwaysShown = expSignAlways; |
| 4123 int32_t digitTotalCount = digitLeftCount + zeroDigitCount + digitRig
htCount; |
| 4124 // The effectiveDecimalPos is the position the decimal is at or |
| 4125 // would be at if there is no decimal. Note that if |
| 4126 // decimalPos<0, then digitTotalCount == digitLeftCount + |
| 4127 // zeroDigitCount. |
| 4128 int32_t effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTo
talCount; |
| 4129 UBool isSigDig = (sigDigitCount > 0); |
| 4130 setSignificantDigitsUsed(isSigDig); |
| 4131 if (isSigDig) { |
| 4132 setMinimumSignificantDigits(sigDigitCount); |
| 4133 setMaximumSignificantDigits(sigDigitCount + digitRightCount); |
| 4134 } else { |
| 4135 int32_t minInt = effectiveDecimalPos - digitLeftCount; |
| 4136 setMinimumIntegerDigits(minInt); |
| 4137 setMaximumIntegerDigits(fUseExponentialNotation |
| 4138 ? digitLeftCount + getMinimumIntegerDigits() |
| 4139 : kDoubleIntegerDigits); |
| 4140 setMaximumFractionDigits(decimalPos >= 0 |
| 4141 ? (digitTotalCount - decimalPos) : 0); |
| 4142 setMinimumFractionDigits(decimalPos >= 0 |
| 4143 ? (digitLeftCount + zeroDigitCount - decimalPos) : 0); |
| 4144 } |
| 4145 setGroupingUsed(groupingCount > 0); |
| 4146 fGroupingSize = (groupingCount > 0) ? groupingCount : 0; |
| 4147 fGroupingSize2 = (groupingCount2 > 0 && groupingCount2 != groupingCo
unt) |
| 4148 ? groupingCount2 : 0; |
| 4149 setMultiplier(multiplier); |
| 4150 setDecimalSeparatorAlwaysShown(decimalPos == 0 |
| 4151 || decimalPos == digitTotalCount); |
| 4152 if (padPos >= 0) { |
| 4153 fPadPosition = (EPadPosition) padPos; |
| 4154 // To compute the format width, first set up sub0Limit - |
| 4155 // sub0Start. Add in prefix/suffix length later. |
| 4156 |
| 4157 // fFormatWidth = prefix.length() + suffix.length() + |
| 4158 // sub0Limit - sub0Start; |
| 4159 fFormatWidth = sub0Limit - sub0Start; |
| 4160 fPad = padChar; |
| 4161 } else { |
| 4162 fFormatWidth = 0; |
| 4163 } |
| 4164 if (roundingPos >= 0) { |
| 4165 roundingInc.setDecimalAt(effectiveDecimalPos - roundingPos); |
| 4166 if (fRoundingIncrement != NULL) { |
| 4167 *fRoundingIncrement = roundingInc; |
| 4168 } else { |
| 4169 fRoundingIncrement = new DigitList(roundingInc); |
| 4170 /* test for NULL */ |
| 4171 if (fRoundingIncrement == NULL) { |
| 4172 status = U_MEMORY_ALLOCATION_ERROR; |
| 4173 delete fPosPrefixPattern; |
| 4174 delete fPosSuffixPattern; |
| 4175 return; |
| 4176 } |
| 4177 } |
| 4178 fRoundingIncrement->getDouble(); // forces caching of double i
n the DigitList, |
| 4179 // makes getting it thread
safe. |
| 4180 fRoundingMode = kRoundHalfEven; |
| 4181 } else { |
| 4182 setRoundingIncrement(0.0); |
| 4183 } |
| 4184 } else { |
| 4185 fNegPrefixPattern = new UnicodeString(prefix); |
| 4186 /* test for NULL */ |
| 4187 if (fNegPrefixPattern == 0) { |
| 4188 status = U_MEMORY_ALLOCATION_ERROR; |
| 4189 return; |
| 4190 } |
| 4191 fNegSuffixPattern = new UnicodeString(suffix); |
| 4192 /* test for NULL */ |
| 4193 if (fNegSuffixPattern == 0) { |
| 4194 delete fNegPrefixPattern; |
| 4195 status = U_MEMORY_ALLOCATION_ERROR; |
| 4196 return; |
| 4197 } |
| 4198 } |
| 4199 } |
| 4200 |
| 4201 if (pattern.length() == 0) { |
| 4202 delete fNegPrefixPattern; |
| 4203 delete fNegSuffixPattern; |
| 4204 fNegPrefixPattern = NULL; |
| 4205 fNegSuffixPattern = NULL; |
| 4206 if (fPosPrefixPattern != NULL) { |
| 4207 fPosPrefixPattern->remove(); |
| 4208 } else { |
| 4209 fPosPrefixPattern = new UnicodeString(); |
| 4210 /* test for NULL */ |
| 4211 if (fPosPrefixPattern == 0) { |
| 4212 status = U_MEMORY_ALLOCATION_ERROR; |
| 4213 return; |
| 4214 } |
| 4215 } |
| 4216 if (fPosSuffixPattern != NULL) { |
| 4217 fPosSuffixPattern->remove(); |
| 4218 } else { |
| 4219 fPosSuffixPattern = new UnicodeString(); |
| 4220 /* test for NULL */ |
| 4221 if (fPosSuffixPattern == 0) { |
| 4222 delete fPosPrefixPattern; |
| 4223 status = U_MEMORY_ALLOCATION_ERROR; |
| 4224 return; |
| 4225 } |
| 4226 } |
| 4227 |
| 4228 setMinimumIntegerDigits(0); |
| 4229 setMaximumIntegerDigits(kDoubleIntegerDigits); |
| 4230 setMinimumFractionDigits(0); |
| 4231 setMaximumFractionDigits(kDoubleFractionDigits); |
| 4232 |
| 4233 fUseExponentialNotation = FALSE; |
| 4234 fCurrencySignCount = 0; |
| 4235 setGroupingUsed(FALSE); |
| 4236 fGroupingSize = 0; |
| 4237 fGroupingSize2 = 0; |
| 4238 setMultiplier(1); |
| 4239 setDecimalSeparatorAlwaysShown(FALSE); |
| 4240 fFormatWidth = 0; |
| 4241 setRoundingIncrement(0.0); |
| 4242 } |
| 4243 |
| 4244 // If there was no negative pattern, or if the negative pattern is |
| 4245 // identical to the positive pattern, then prepend the minus sign to the |
| 4246 // positive pattern to form the negative pattern. |
| 4247 if (fNegPrefixPattern == NULL || |
| 4248 (*fNegPrefixPattern == *fPosPrefixPattern |
| 4249 && *fNegSuffixPattern == *fPosSuffixPattern)) { |
| 4250 _copy_us_ptr(&fNegSuffixPattern, fPosSuffixPattern); |
| 4251 if (fNegPrefixPattern == NULL) { |
| 4252 fNegPrefixPattern = new UnicodeString(); |
| 4253 /* test for NULL */ |
| 4254 if (fNegPrefixPattern == 0) { |
| 4255 status = U_MEMORY_ALLOCATION_ERROR; |
| 4256 return; |
| 4257 } |
| 4258 } else { |
| 4259 fNegPrefixPattern->remove(); |
| 4260 } |
| 4261 fNegPrefixPattern->append(kQuote).append(kPatternMinus) |
| 4262 .append(*fPosPrefixPattern); |
| 4263 } |
| 4264 #ifdef FMT_DEBUG |
| 4265 UnicodeString s; |
| 4266 s.append("\"").append(pattern).append("\"->"); |
| 4267 debugout(s); |
| 4268 #endif |
| 4269 |
| 4270 // save the pattern |
| 4271 fFormatPattern = pattern; |
| 4272 } |
| 4273 |
| 4274 |
| 4275 void |
| 4276 DecimalFormat::expandAffixAdjustWidth(const UnicodeString* pluralCount) { |
| 4277 expandAffixes(pluralCount); |
| 4278 if (fFormatWidth > 0) { |
| 4279 // Finish computing format width (see above) |
| 4280 // TODO: how to handle fFormatWidth, |
| 4281 // need to save in f(Plural)AffixesForCurrecy? |
| 4282 fFormatWidth += fPositivePrefix.length() + fPositiveSuffix.length(); |
| 4283 } |
| 4284 } |
| 4285 |
| 4286 |
| 4287 void |
| 4288 DecimalFormat::applyPattern(const UnicodeString& pattern, |
| 4289 UBool localized, |
| 4290 UParseError& parseError, |
| 4291 UErrorCode& status) |
| 4292 { |
| 4293 // do the following re-set first. since they change private data by |
| 4294 // apply pattern again. |
| 4295 if (pattern.indexOf(kCurrencySign) != -1) { |
| 4296 if (fCurrencyPluralInfo == NULL) { |
| 4297 // initialize currencyPluralInfo if needed |
| 4298 fCurrencyPluralInfo = new CurrencyPluralInfo(fSymbols->getLocale(),
status); |
| 4299 } |
| 4300 if (fAffixPatternsForCurrency == NULL) { |
| 4301 setupCurrencyAffixPatterns(status); |
| 4302 } |
| 4303 if (pattern.indexOf(fgTripleCurrencySign) != -1) { |
| 4304 // only setup the affixes of the current pattern. |
| 4305 setupCurrencyAffixes(pattern, TRUE, FALSE, status); |
| 4306 } |
| 4307 } |
| 4308 applyPatternWithoutExpandAffix(pattern, localized, parseError, status); |
| 4309 expandAffixAdjustWidth(NULL); |
| 4310 } |
| 4311 |
| 4312 |
| 4313 void |
| 4314 DecimalFormat::applyPatternInternally(const UnicodeString& pluralCount, |
| 4315 const UnicodeString& pattern, |
| 4316 UBool localized, |
| 4317 UParseError& parseError, |
| 4318 UErrorCode& status) { |
| 4319 applyPatternWithoutExpandAffix(pattern, localized, parseError, status); |
| 4320 expandAffixAdjustWidth(&pluralCount); |
| 4321 } |
| 4322 |
| 4323 |
| 4324 /** |
| 4325 * Sets the maximum number of digits allowed in the integer portion of a |
| 4326 * number. This override limits the integer digit count to 309. |
| 4327 * @see NumberFormat#setMaximumIntegerDigits |
| 4328 */ |
| 4329 void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { |
| 4330 NumberFormat::setMaximumIntegerDigits(_min(newValue, kDoubleIntegerDigits)); |
| 4331 } |
| 4332 |
| 4333 /** |
| 4334 * Sets the minimum number of digits allowed in the integer portion of a |
| 4335 * number. This override limits the integer digit count to 309. |
| 4336 * @see NumberFormat#setMinimumIntegerDigits |
| 4337 */ |
| 4338 void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { |
| 4339 NumberFormat::setMinimumIntegerDigits(_min(newValue, kDoubleIntegerDigits)); |
| 4340 } |
| 4341 |
| 4342 /** |
| 4343 * Sets the maximum number of digits allowed in the fraction portion of a |
| 4344 * number. This override limits the fraction digit count to 340. |
| 4345 * @see NumberFormat#setMaximumFractionDigits |
| 4346 */ |
| 4347 void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { |
| 4348 NumberFormat::setMaximumFractionDigits(_min(newValue, kDoubleFractionDigits)
); |
| 4349 } |
| 4350 |
| 4351 /** |
| 4352 * Sets the minimum number of digits allowed in the fraction portion of a |
| 4353 * number. This override limits the fraction digit count to 340. |
| 4354 * @see NumberFormat#setMinimumFractionDigits |
| 4355 */ |
| 4356 void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { |
| 4357 NumberFormat::setMinimumFractionDigits(_min(newValue, kDoubleFractionDigits)
); |
| 4358 } |
| 4359 |
| 4360 int32_t DecimalFormat::getMinimumSignificantDigits() const { |
| 4361 return fMinSignificantDigits; |
| 4362 } |
| 4363 |
| 4364 int32_t DecimalFormat::getMaximumSignificantDigits() const { |
| 4365 return fMaxSignificantDigits; |
| 4366 } |
| 4367 |
| 4368 void DecimalFormat::setMinimumSignificantDigits(int32_t min) { |
| 4369 if (min < 1) { |
| 4370 min = 1; |
| 4371 } |
| 4372 // pin max sig dig to >= min |
| 4373 int32_t max = _max(fMaxSignificantDigits, min); |
| 4374 fMinSignificantDigits = min; |
| 4375 fMaxSignificantDigits = max; |
| 4376 } |
| 4377 |
| 4378 void DecimalFormat::setMaximumSignificantDigits(int32_t max) { |
| 4379 if (max < 1) { |
| 4380 max = 1; |
| 4381 } |
| 4382 // pin min sig dig to 1..max |
| 4383 U_ASSERT(fMinSignificantDigits >= 1); |
| 4384 int32_t min = _min(fMinSignificantDigits, max); |
| 4385 fMinSignificantDigits = min; |
| 4386 fMaxSignificantDigits = max; |
| 4387 } |
| 4388 |
| 4389 UBool DecimalFormat::areSignificantDigitsUsed() const { |
| 4390 return fUseSignificantDigits; |
| 4391 } |
| 4392 |
| 4393 void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { |
| 4394 fUseSignificantDigits = useSignificantDigits; |
| 4395 } |
| 4396 |
| 4397 void DecimalFormat::setCurrencyInternally(const UChar* theCurrency, |
| 4398 UErrorCode& ec) { |
| 4399 // If we are a currency format, then modify our affixes to |
| 4400 // encode the currency symbol for the given currency in our |
| 4401 // locale, and adjust the decimal digits and rounding for the |
| 4402 // given currency. |
| 4403 |
| 4404 // Note: The code is ordered so that this object is *not changed* |
| 4405 // until we are sure we are going to succeed. |
| 4406 |
| 4407 // NULL or empty currency is *legal* and indicates no currency. |
| 4408 UBool isCurr = (theCurrency && *theCurrency); |
| 4409 |
| 4410 double rounding = 0.0; |
| 4411 int32_t frac = 0; |
| 4412 if (fCurrencySignCount > fgCurrencySignCountZero && isCurr) { |
| 4413 rounding = ucurr_getRoundingIncrement(theCurrency, &ec); |
| 4414 frac = ucurr_getDefaultFractionDigits(theCurrency, &ec); |
| 4415 } |
| 4416 |
| 4417 NumberFormat::setCurrency(theCurrency, ec); |
| 4418 if (U_FAILURE(ec)) return; |
| 4419 |
| 4420 if (fCurrencySignCount > fgCurrencySignCountZero) { |
| 4421 // NULL or empty currency is *legal* and indicates no currency. |
| 4422 if (isCurr) { |
| 4423 setRoundingIncrement(rounding); |
| 4424 setMinimumFractionDigits(frac); |
| 4425 setMaximumFractionDigits(frac); |
| 4426 } |
| 4427 expandAffixes(NULL); |
| 4428 } |
| 4429 } |
| 4430 |
| 4431 void DecimalFormat::setCurrency(const UChar* theCurrency, UErrorCode& ec) { |
| 4432 // set the currency before compute affixes to get the right currency names |
| 4433 NumberFormat::setCurrency(theCurrency, ec); |
| 4434 if (fFormatPattern.indexOf(fgTripleCurrencySign) != -1) { |
| 4435 UnicodeString savedPtn = fFormatPattern; |
| 4436 setupCurrencyAffixes(fFormatPattern, TRUE, TRUE, ec); |
| 4437 UParseError parseErr; |
| 4438 applyPattern(savedPtn, FALSE, parseErr, ec); |
| 4439 } |
| 4440 // set the currency after apply pattern to get the correct rounding/fraction |
| 4441 setCurrencyInternally(theCurrency, ec); |
| 4442 } |
| 4443 |
| 4444 // Deprecated variant with no UErrorCode parameter |
| 4445 void DecimalFormat::setCurrency(const UChar* theCurrency) { |
| 4446 UErrorCode ec = U_ZERO_ERROR; |
| 4447 setCurrency(theCurrency, ec); |
| 4448 } |
| 4449 |
| 4450 void DecimalFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { |
| 4451 if (fSymbols == NULL) { |
| 4452 ec = U_MEMORY_ALLOCATION_ERROR; |
| 4453 return; |
| 4454 } |
| 4455 ec = U_ZERO_ERROR; |
| 4456 const UChar* c = getCurrency(); |
| 4457 if (*c == 0) { |
| 4458 const UnicodeString &intl = |
| 4459 fSymbols->getConstSymbol(DecimalFormatSymbols::kIntlCurrencySymbol); |
| 4460 c = intl.getBuffer(); // ok for intl to go out of scope |
| 4461 } |
| 4462 u_strncpy(result, c, 3); |
| 4463 result[3] = 0; |
| 4464 } |
| 4465 |
| 4466 /** |
| 4467 * Return the number of fraction digits to display, or the total |
| 4468 * number of digits for significant digit formats and exponential |
| 4469 * formats. |
| 4470 */ |
| 4471 int32_t |
| 4472 DecimalFormat::precision() const { |
| 4473 if (areSignificantDigitsUsed()) { |
| 4474 return getMaximumSignificantDigits(); |
| 4475 } else if (fUseExponentialNotation) { |
| 4476 return getMinimumIntegerDigits() + getMaximumFractionDigits(); |
| 4477 } else { |
| 4478 return getMaximumFractionDigits(); |
| 4479 } |
| 4480 } |
| 4481 |
| 4482 |
| 4483 // TODO: template algorithm |
| 4484 Hashtable* |
| 4485 DecimalFormat::initHashForAffix(UErrorCode& status) { |
| 4486 if ( U_FAILURE(status) ) { |
| 4487 return NULL; |
| 4488 } |
| 4489 Hashtable* hTable; |
| 4490 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { |
| 4491 status = U_MEMORY_ALLOCATION_ERROR; |
| 4492 return NULL; |
| 4493 } |
| 4494 hTable->setValueComparator(decimfmtAffixValueComparator); |
| 4495 return hTable; |
| 4496 } |
| 4497 |
| 4498 Hashtable* |
| 4499 DecimalFormat::initHashForAffixPattern(UErrorCode& status) { |
| 4500 if ( U_FAILURE(status) ) { |
| 4501 return NULL; |
| 4502 } |
| 4503 Hashtable* hTable; |
| 4504 if ( (hTable = new Hashtable(TRUE, status)) == NULL ) { |
| 4505 status = U_MEMORY_ALLOCATION_ERROR; |
| 4506 return NULL; |
| 4507 } |
| 4508 hTable->setValueComparator(decimfmtAffixPatternValueComparator); |
| 4509 return hTable; |
| 4510 } |
| 4511 |
| 4512 void |
| 4513 DecimalFormat::deleteHashForAffix(Hashtable*& table) |
| 4514 { |
| 4515 if ( table == NULL ) { |
| 4516 return; |
| 4517 } |
| 4518 int32_t pos = -1; |
| 4519 const UHashElement* element = NULL; |
| 4520 while ( (element = table->nextElement(pos)) != NULL ) { |
| 4521 const UHashTok keyTok = element->key; |
| 4522 const UHashTok valueTok = element->value; |
| 4523 const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.pointer; |
| 4524 delete value; |
| 4525 } |
| 4526 delete table; |
| 4527 table = NULL; |
| 4528 } |
| 4529 |
| 4530 |
| 4531 |
| 4532 void |
| 4533 DecimalFormat::deleteHashForAffixPattern() |
| 4534 { |
| 4535 if ( fAffixPatternsForCurrency == NULL ) { |
| 4536 return; |
| 4537 } |
| 4538 int32_t pos = -1; |
| 4539 const UHashElement* element = NULL; |
| 4540 while ( (element = fAffixPatternsForCurrency->nextElement(pos)) != NULL ) { |
| 4541 const UHashTok keyTok = element->key; |
| 4542 const UHashTok valueTok = element->value; |
| 4543 const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)value
Tok.pointer; |
| 4544 delete value; |
| 4545 } |
| 4546 delete fAffixPatternsForCurrency; |
| 4547 fAffixPatternsForCurrency = NULL; |
| 4548 } |
| 4549 |
| 4550 |
| 4551 void |
| 4552 DecimalFormat::copyHashForAffixPattern(const Hashtable* source, |
| 4553 Hashtable* target, |
| 4554 UErrorCode& status) { |
| 4555 if ( U_FAILURE(status) ) { |
| 4556 return; |
| 4557 } |
| 4558 int32_t pos = -1; |
| 4559 const UHashElement* element = NULL; |
| 4560 if ( source ) { |
| 4561 while ( (element = source->nextElement(pos)) != NULL ) { |
| 4562 const UHashTok keyTok = element->key; |
| 4563 const UnicodeString* key = (UnicodeString*)keyTok.pointer; |
| 4564 const UHashTok valueTok = element->value; |
| 4565 const AffixPatternsForCurrency* value = (AffixPatternsForCurrency*)v
alueTok.pointer; |
| 4566 AffixPatternsForCurrency* copy = new AffixPatternsForCurrency( |
| 4567 value->negPrefixPatternForCurrency, |
| 4568 value->negSuffixPatternForCurrency, |
| 4569 value->posPrefixPatternForCurrency, |
| 4570 value->posSuffixPatternForCurrency, |
| 4571 value->patternType); |
| 4572 target->put(UnicodeString(*key), copy, status); |
| 4573 if ( U_FAILURE(status) ) { |
| 4574 return; |
| 4575 } |
| 4576 } |
| 4577 } |
| 4578 } |
| 4579 |
| 4580 |
| 4581 |
| 4582 void |
| 4583 DecimalFormat::copyHashForAffix(const Hashtable* source, |
| 4584 Hashtable* target, |
| 4585 UErrorCode& status) { |
| 4586 if ( U_FAILURE(status) ) { |
| 4587 return; |
| 4588 } |
| 4589 int32_t pos = -1; |
| 4590 const UHashElement* element = NULL; |
| 4591 if ( source ) { |
| 4592 while ( (element = source->nextElement(pos)) != NULL ) { |
| 4593 const UHashTok keyTok = element->key; |
| 4594 const UnicodeString* key = (UnicodeString*)keyTok.pointer; |
| 4595 |
| 4596 const UHashTok valueTok = element->value; |
| 4597 const AffixesForCurrency* value = (AffixesForCurrency*)valueTok.poin
ter; |
| 4598 AffixesForCurrency* copy = new AffixesForCurrency( |
| 4599 value->negPrefixForCurrency, |
| 4600 value->negSuffixForCurrency, |
| 4601 value->posPrefixForCurrency, |
| 4602 value->posSuffixForCurrency); |
| 4603 target->put(UnicodeString(*key), copy, status); |
| 4604 if ( U_FAILURE(status) ) { |
| 4605 return; |
| 4606 } |
| 4607 } |
| 4608 } |
| 4609 } |
| 4610 |
| 4611 U_NAMESPACE_END |
| 4612 |
| 4613 #endif /* #if !UCONFIG_NO_FORMATTING */ |
| 4614 |
| 4615 //eof |
OLD | NEW |