| /* |
| ******************************************************************************* |
| * Copyright (C) 1997-1999, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| * |
| * File DECIMFMT.CPP |
| * |
| * Modification History: |
| * |
| * Date Name Description |
| * 02/19/97 aliu Converted from java. |
| * 03/20/97 clhuang Implemented with new APIs. |
| * 03/31/97 aliu Moved isLONG_MIN to DigitList, and fixed it. |
| * 04/3/97 aliu Rewrote parsing and formatting completely, and |
| * cleaned up and debugged. Actually works now. |
| * Implemented NAN and INF handling, for both parsing |
| * and formatting. Extensive testing & debugging. |
| * 04/10/97 aliu Modified to compile on AIX. |
| * 04/16/97 aliu Rewrote to use DigitList, which has been resurrected. |
| * Changed DigitCount to int per code review. |
| * 07/09/97 helena Made ParsePosition into a class. |
| * 08/26/97 aliu Extensive changes to applyPattern; completely |
| * rewritten from the Java. |
| * 09/09/97 aliu Ported over support for exponential formats. |
| * 07/20/98 stephen JDK 1.2 sync up. |
| * Various instances of '0' replaced with 'NULL' |
| * Check for grouping size in subFormat() |
| * Brought subParse() in line with Java 1.2 |
| * Added method appendAffix() |
| * 08/24/1998 srl Removed Mutex calls. This is not a thread safe class! |
| * 02/22/99 stephen Removed character literals for EBCDIC safety |
| * 06/24/99 helena Integrated Alan's NF enhancements and Java2 bug fixes |
| * 06/28/99 stephen Fixed bugs in toPattern(). |
| * 06/29/99 stephen Fixed operator= to copy fFormatWidth, fPad, |
| * fPadPosition |
| ******************************************************************************** |
| */ |
| |
| #include "unicode/decimfmt.h" |
| #include "digitlst.h" |
| #include "unicode/dcfmtsym.h" |
| #include "unicode/resbund.h" |
| #include "unicode/unicode.h" |
| #include "cmemory.h" |
| #include <float.h> |
| #include <limits.h> |
| |
| // #define DEBUG |
| |
| #ifdef DEBUG |
| #include <stdio.h> |
| static void debugout(UnicodeString s) { |
| char buf[2000]; |
| s.extract((UTextOffset) 0, s.length(), buf); |
| buf[s.length()] = 0; |
| printf("%s", buf); |
| } |
| #define debug(x) printf("%s", x); |
| #else |
| #define debugout(x) |
| #define debug(x) |
| #endif |
| |
| // ***************************************************************************** |
| // class DecimalFormat |
| // ***************************************************************************** |
| |
| char DecimalFormat::fgClassID = 0; // Value is irrelevan |
| |
| // Constants for characters used in programmatic (unlocalized) patterns. |
| const UChar DecimalFormat::kPatternZeroDigit = 0x0030 /*'0'*/; |
| const UChar DecimalFormat::kPatternGroupingSeparator = 0x002C /*','*/; |
| const UChar DecimalFormat::kPatternDecimalSeparator = 0x002E /*'.'*/; |
| const UChar DecimalFormat::kPatternPerMill = 0x2030; |
| const UChar DecimalFormat::kPatternPercent = 0x0025 /*'%'*/; |
| const UChar DecimalFormat::kPatternDigit = 0x0023 /*'#'*/; |
| const UChar DecimalFormat::kPatternSeparator = 0x003B /*';'*/; |
| const UChar DecimalFormat::kPatternExponent = 0x0045 /*'E'*/; |
| const UChar DecimalFormat::kPatternPlus = 0x002B /*'+'*/; |
| const UChar DecimalFormat::kPatternMinus = 0x002D /*'-'*/; |
| const UChar DecimalFormat::kPatternPadEscape = 0x002A /*'*'*/; |
| const UChar DecimalFormat::kCurrencySign = 0x00A4; |
| const UChar DecimalFormat::kQuote = 0x0027 /*'\''*/; |
| |
| const int8_t DecimalFormat::fgMaxDigit = 9; |
| |
| const int32_t DecimalFormat::kDoubleIntegerDigits = 309; |
| const int32_t DecimalFormat::kDoubleFractionDigits = 340; |
| |
| /** |
| * These are the tags we expect to see in normal resource bundle files associated |
| * with a locale. |
| */ |
| const char *DecimalFormat::fgNumberPatterns="NumberPatterns"; |
| |
| //------------------------------------------------------------------------------ |
| // Constructs a DecimalFormat instance in the default locale. |
| |
| DecimalFormat::DecimalFormat(UErrorCode& status) |
| : NumberFormat(), |
| fPosPrefixPattern(0), |
| fNegPrefixPattern(0), |
| fPosSuffixPattern(0), |
| fNegSuffixPattern(0), |
| fSymbols(0) |
| { |
| construct(status); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Constructs a DecimalFormat instance with the specified number format |
| // pattern in the default locale. |
| |
| DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| UErrorCode& status) |
| : NumberFormat(), |
| fPosPrefixPattern(0), |
| fNegPrefixPattern(0), |
| fPosSuffixPattern(0), |
| fNegSuffixPattern(0), |
| fSymbols(0) |
| { |
| construct(status, &pattern); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Constructs a DecimalFormat instance with the specified number format |
| // pattern and the number format symbols in the default locale. The |
| // created instance owns the symbols. |
| |
| DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| DecimalFormatSymbols* symbolsToAdopt, |
| UErrorCode& status) |
| : NumberFormat(), |
| fPosPrefixPattern(0), |
| fNegPrefixPattern(0), |
| fPosSuffixPattern(0), |
| fNegSuffixPattern(0), |
| fSymbols(0) |
| { |
| if (symbolsToAdopt == NULL) status = U_ILLEGAL_ARGUMENT_ERROR; |
| construct(status, &pattern, symbolsToAdopt); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Constructs a DecimalFormat instance with the specified number format |
| // pattern and the number format symbols in the default locale. The |
| // created instance owns the clone of the symbols. |
| |
| DecimalFormat::DecimalFormat(const UnicodeString& pattern, |
| const DecimalFormatSymbols& symbols, |
| UErrorCode& status) |
| : NumberFormat(), |
| fPosPrefixPattern(0), |
| fNegPrefixPattern(0), |
| fPosSuffixPattern(0), |
| fNegSuffixPattern(0), |
| fSymbols(0) |
| { |
| construct(status, &pattern, new DecimalFormatSymbols(symbols)); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Constructs a DecimalFormat instance with the specified number format |
| // pattern and the number format symbols in the desired locale. The |
| // created instance owns the symbols. |
| |
| void |
| DecimalFormat::construct(UErrorCode& status, |
| const UnicodeString* pattern, |
| DecimalFormatSymbols* symbolsToAdopt, |
| const Locale& locale) |
| { |
| fSymbols = symbolsToAdopt; // Do this BEFORE aborting on status failure!!! |
| fDigitList = new DigitList(); // Do this BEFORE aborting on status failure!!! |
| fRoundingIncrement = NULL; |
| fRoundingDouble = 0.0; |
| fRoundingMode = kRoundHalfEven; |
| fPad = kPatternPadEscape; |
| fPadPosition = kPadBeforePrefix; |
| if (U_FAILURE(status)) return; |
| |
| fPosPrefixPattern = fPosSuffixPattern = NULL; |
| fNegPrefixPattern = fNegSuffixPattern = NULL; |
| fMultiplier = 1; |
| fGroupingSize = 3; |
| fDecimalSeparatorAlwaysShown = FALSE; |
| fIsCurrencyFormat = FALSE; |
| fUseExponentialNotation = FALSE; |
| fMinExponentDigits = 0; |
| |
| if (fSymbols == NULL) fSymbols = new DecimalFormatSymbols(locale, status); |
| |
| UnicodeString str; |
| // Uses the default locale's number format pattern if there isn't |
| // one specified. |
| if (pattern == NULL) |
| { |
| ResourceBundle resource(Locale::getDataDirectory(), Locale::getDefault(), status); |
| resource.getArrayItem(fgNumberPatterns, 0, str, status); |
| pattern = &str; |
| } |
| |
| if (U_FAILURE(status)) return; |
| |
| applyPattern(*pattern, FALSE /*not localized*/, status); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| DecimalFormat::~DecimalFormat() |
| { |
| delete fSymbols; |
| delete fDigitList; |
| delete fPosPrefixPattern; |
| delete fPosSuffixPattern; |
| delete fNegPrefixPattern; |
| delete fNegSuffixPattern; |
| delete fRoundingIncrement; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // copy constructor |
| |
| DecimalFormat::DecimalFormat(const DecimalFormat &source) |
| : NumberFormat(source), |
| fSymbols(NULL), |
| fDigitList(NULL), |
| fPosPrefixPattern(NULL), |
| fPosSuffixPattern(NULL), |
| fNegPrefixPattern(NULL), |
| fNegSuffixPattern(NULL), |
| fRoundingIncrement(NULL) |
| { |
| *this = source; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // assignment operator |
| // Note that fDigitList is not considered a significant part of the |
| // DecimalFormat because it's used as a buffer to process the numbers. |
| |
| static void _copy_us_ptr(UnicodeString** pdest, const UnicodeString* source) { |
| if (source == NULL) { |
| delete *pdest; |
| *pdest = NULL; |
| } else if (*pdest == NULL) { |
| *pdest = new UnicodeString(*source); |
| } else { |
| **pdest = *source; |
| } |
| } |
| |
| DecimalFormat& |
| DecimalFormat::operator=(const DecimalFormat& rhs) |
| { |
| if(this != &rhs) { |
| NumberFormat::operator=(rhs); |
| fPositivePrefix = rhs.fPositivePrefix; |
| fPositiveSuffix = rhs.fPositiveSuffix; |
| fNegativePrefix = rhs.fNegativePrefix; |
| fNegativeSuffix = rhs.fNegativeSuffix; |
| _copy_us_ptr(&fPosPrefixPattern, rhs.fPosPrefixPattern); |
| _copy_us_ptr(&fPosSuffixPattern, rhs.fPosSuffixPattern); |
| _copy_us_ptr(&fNegPrefixPattern, rhs.fNegPrefixPattern); |
| _copy_us_ptr(&fNegSuffixPattern, rhs.fNegSuffixPattern); |
| if(rhs.fRoundingIncrement == NULL) { |
| delete fRoundingIncrement; |
| fRoundingIncrement = NULL; |
| } |
| else if(fRoundingIncrement == NULL) { |
| fRoundingIncrement = new DigitList(*rhs.fRoundingIncrement); |
| } |
| else { |
| *fRoundingIncrement = *rhs.fRoundingIncrement; |
| } |
| fRoundingDouble = rhs.fRoundingDouble; |
| fMultiplier = rhs.fMultiplier; |
| fGroupingSize = rhs.fGroupingSize; |
| fDecimalSeparatorAlwaysShown = rhs.fDecimalSeparatorAlwaysShown; |
| if(fSymbols == NULL) |
| fSymbols = new DecimalFormatSymbols(*rhs.fSymbols); |
| else |
| *fSymbols = *rhs.fSymbols; |
| fUseExponentialNotation = rhs.fUseExponentialNotation; |
| /*Bertrand A. D. Update 98.03.17*/ |
| fIsCurrencyFormat = rhs.fIsCurrencyFormat; |
| /*end of Update*/ |
| fMinExponentDigits = rhs.fMinExponentDigits; |
| if (fDigitList == NULL) fDigitList = new DigitList(); |
| |
| /* sfb 990629 */ |
| fFormatWidth = rhs.fFormatWidth; |
| fPad = rhs.fPad; |
| fPadPosition = rhs.fPadPosition; |
| /* end sfb */ |
| } |
| return *this; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| bool_t |
| DecimalFormat::operator==(const Format& that) const |
| { |
| if (this == &that) return TRUE; |
| |
| if (getDynamicClassID() != that.getDynamicClassID()) return FALSE; |
| |
| const DecimalFormat* other = (DecimalFormat*)&that; |
| |
| #if 0 |
| // This code makes it easy to determine why two format objects that should |
| // be equal aren't. |
| bool_t first = TRUE; |
| if (!NumberFormat::operator==(that)) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("NumberFormat::!="); |
| } |
| if (!((fPosPrefixPattern == other->fPosPrefixPattern && // both null |
| fPositivePrefix == other->fPositivePrefix) |
| || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 && |
| *fPosPrefixPattern == *other->fPosPrefixPattern))) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Pos Prefix !="); |
| } |
| if (!((fPosSuffixPattern == other->fPosSuffixPattern && // both null |
| fPositiveSuffix == other->fPositiveSuffix) |
| || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 && |
| *fPosSuffixPattern == *other->fPosSuffixPattern))) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Pos Suffix !="); |
| } |
| if (!((fNegPrefixPattern == other->fNegPrefixPattern && // both null |
| fNegativePrefix == other->fNegativePrefix) |
| || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 && |
| *fNegPrefixPattern == *other->fNegPrefixPattern))) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Neg Prefix "); |
| if (fNegPrefixPattern == NULL) { |
| debug("NULL("); |
| debugout(fNegativePrefix); |
| debug(")"); |
| } else { |
| debugout(*fNegPrefixPattern); |
| } |
| debug(" != "); |
| if (other->fNegPrefixPattern == NULL) { |
| debug("NULL("); |
| debugout(other->fNegativePrefix); |
| debug(")"); |
| } else { |
| debugout(*other->fNegPrefixPattern); |
| } |
| } |
| if (!((fNegSuffixPattern == other->fNegSuffixPattern && // both null |
| fNegativeSuffix == other->fNegativeSuffix) |
| || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 && |
| *fNegSuffixPattern == *other->fNegSuffixPattern))) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Neg Suffix "); |
| if (fNegSuffixPattern == NULL) { |
| debug("NULL("); |
| debugout(fNegativeSuffix); |
| debug(")"); |
| } else { |
| debugout(*fNegSuffixPattern); |
| } |
| debug(" != "); |
| if (other->fNegSuffixPattern == NULL) { |
| debug("NULL("); |
| debugout(other->fNegativeSuffix); |
| debug(")"); |
| } else { |
| debugout(*other->fNegSuffixPattern); |
| } |
| } |
| if (!((fRoundingIncrement == other->fRoundingIncrement) // both null |
| || (fRoundingIncrement != NULL && |
| other->fRoundingIncrement != NULL && |
| *fRoundingIncrement == *other->fRoundingIncrement))) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Rounding Increment !="); |
| } |
| if (fMultiplier != other->fMultiplier) { |
| if (first) { printf("[ "); first = FALSE; } |
| printf("Multiplier %ld != %ld", fMultiplier, other->fMultiplier); |
| } |
| if (fGroupingSize != other->fGroupingSize) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| printf("Grouping Size %ld != %ld", fGroupingSize, other->fGroupingSize); |
| } |
| if (fDecimalSeparatorAlwaysShown != other->fDecimalSeparatorAlwaysShown) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| printf("Dec Sep Always %d != %d", fDecimalSeparatorAlwaysShown, other->fDecimalSeparatorAlwaysShown); |
| } |
| if (fUseExponentialNotation != other->fUseExponentialNotation) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Use Exp !="); |
| } |
| if (!(!fUseExponentialNotation || |
| fMinExponentDigits != other->fMinExponentDigits)) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Exp Digits !="); |
| } |
| if (*fSymbols != *(other->fSymbols)) { |
| if (first) { printf("[ "); first = FALSE; } else { printf(", "); } |
| debug("Symbols !="); |
| } |
| if (!first) { printf(" ]"); } |
| #endif |
| |
| return (NumberFormat::operator==(that) && |
| ((fPosPrefixPattern == other->fPosPrefixPattern && // both null |
| fPositivePrefix == other->fPositivePrefix) |
| || (fPosPrefixPattern != 0 && other->fPosPrefixPattern != 0 && |
| *fPosPrefixPattern == *other->fPosPrefixPattern)) && |
| ((fPosSuffixPattern == other->fPosSuffixPattern && // both null |
| fPositiveSuffix == other->fPositiveSuffix) |
| || (fPosSuffixPattern != 0 && other->fPosSuffixPattern != 0 && |
| *fPosSuffixPattern == *other->fPosSuffixPattern)) && |
| ((fNegPrefixPattern == other->fNegPrefixPattern && // both null |
| fNegativePrefix == other->fNegativePrefix) |
| || (fNegPrefixPattern != 0 && other->fNegPrefixPattern != 0 && |
| *fNegPrefixPattern == *other->fNegPrefixPattern)) && |
| ((fNegSuffixPattern == other->fNegSuffixPattern && // both null |
| fNegativeSuffix == other->fNegativeSuffix) |
| || (fNegSuffixPattern != 0 && other->fNegSuffixPattern != 0 && |
| *fNegSuffixPattern == *other->fNegSuffixPattern)) && |
| ((fRoundingIncrement == other->fRoundingIncrement) // both null |
| || (fRoundingIncrement != NULL && |
| other->fRoundingIncrement != NULL && |
| *fRoundingIncrement == *other->fRoundingIncrement)) && |
| fMultiplier == other->fMultiplier && |
| fGroupingSize == other->fGroupingSize && |
| fDecimalSeparatorAlwaysShown == other->fDecimalSeparatorAlwaysShown && |
| fUseExponentialNotation == other->fUseExponentialNotation && |
| (!fUseExponentialNotation || |
| fMinExponentDigits == other->fMinExponentDigits) && |
| *fSymbols == *(other->fSymbols)); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| Format* |
| DecimalFormat::clone() const |
| { |
| return new DecimalFormat(*this); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| UnicodeString& |
| DecimalFormat::format(int32_t number, |
| UnicodeString& result, |
| FieldPosition& fieldPosition) const |
| { |
| // Clears field positions. |
| fieldPosition.setBeginIndex(0); |
| fieldPosition.setEndIndex(0); |
| |
| // If we are to do rounding, we need to move into the BigDecimal |
| // domain in order to do divide/multiply correctly. |
| if (fRoundingIncrement != NULL) { |
| return format((double) number, result, fieldPosition); |
| } |
| |
| bool_t isNegative = (number < 0); |
| if (isNegative) number = -number; // NOTE: number will still be negative if it is LONG_MIN |
| |
| // In general, long values always represent real finite numbers, so |
| // we don't have to check for +/- Infinity or NaN. However, there |
| // is one case we have to be careful of: The multiplier can push |
| // a number near MIN_VALUE or MAX_VALUE outside the legal range. We |
| // check for this before multiplying, and if it happens we use doubles |
| // instead, trading off accuracy for range. |
| if (fMultiplier != 1 && fMultiplier != 0) |
| { |
| bool_t useDouble = FALSE; |
| |
| if (number < 0) // This can only happen if number == Long.MIN_VALUE |
| { |
| int32_t cutoff = LONG_MIN / fMultiplier; |
| useDouble = (number < cutoff); |
| } |
| else |
| { |
| int32_t cutoff = T_INT32_MAX / fMultiplier; |
| useDouble = (number > cutoff); |
| } |
| // use double to format the number instead so we don't get out |
| // of range errors. |
| if (useDouble) |
| { |
| double dnumber = (double)(isNegative ? -number : number); |
| return format(dnumber, result, fieldPosition); |
| } |
| } |
| |
| number *= fMultiplier; |
| DecimalFormat *non_const = (DecimalFormat*)this; |
| non_const->fDigitList->set(number, fUseExponentialNotation ? |
| getMinimumIntegerDigits() + getMaximumFractionDigits() : 0); |
| |
| return subformat(result, fieldPosition, isNegative, TRUE); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| UnicodeString& |
| DecimalFormat::format( double number, |
| UnicodeString& result, |
| FieldPosition& fieldPosition) const |
| { |
| // Clears field positions. |
| fieldPosition.setBeginIndex(0); |
| fieldPosition.setEndIndex(0); |
| |
| // Special case for NaN, sets the begin and end index to be the |
| // the string length of localized name of NaN. |
| if (uprv_isNaN(number)) |
| { |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setBeginIndex(result.length()); |
| |
| UnicodeString nan; |
| result += fSymbols->getNaN(nan); |
| |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setEndIndex(result.length()); |
| |
| addPadding(result, FALSE, FALSE /*ignored*/); |
| return result; |
| } |
| |
| /* Detecting whether a double is negative is easy with the exception of |
| * the value -0.0. This is a double which has a zero mantissa (and |
| * exponent), but a negative sign bit. It is semantically distinct from |
| * a zero with a positive sign bit, and this distinction is important |
| * to certain kinds of computations. However, it's a little tricky to |
| * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may |
| * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) == |
| * -Infinity. Proper detection of -0.0 is needed to deal with the |
| * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. |
| */ |
| bool_t isNegative = uprv_isNegative(number); |
| if (isNegative) number = -number; |
| |
| // Do this BEFORE checking to see if value is infinite! Sets the |
| // begin and end index to be length of the string composed of |
| // localized name of Infinite and the positive/negative localized |
| // signs. |
| |
| if (fMultiplier != 1) number *= fMultiplier; |
| |
| // Apply rounding after multiplier |
| if (fRoundingIncrement != NULL) { |
| number = fRoundingDouble |
| * round(number / fRoundingDouble, fRoundingMode, isNegative); |
| } |
| |
| // Special case for INFINITE, |
| if (uprv_isInfinite(number)) |
| { |
| result += (isNegative ? fNegativePrefix : fPositivePrefix); |
| |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setBeginIndex(result.length()); |
| |
| UnicodeString inf; |
| result += fSymbols->getInfinity(inf); |
| |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setEndIndex(result.length()); |
| |
| result += (isNegative ? fNegativeSuffix : fPositiveSuffix); |
| |
| addPadding(result, TRUE, isNegative); |
| return result; |
| } |
| |
| // At this point we are guaranteed a nonnegative finite |
| // number. |
| DecimalFormat* non_const = (DecimalFormat*)this; |
| // Sets up the digit list buffer with the number. |
| // Please see digitlst.cpp for the details regarding DigitList. |
| non_const->fDigitList->set(number, fUseExponentialNotation ? |
| getMinimumIntegerDigits() + getMaximumFractionDigits() : |
| getMaximumFractionDigits(), |
| !fUseExponentialNotation); |
| |
| return subformat(result, fieldPosition, isNegative, FALSE); |
| } |
| |
| /** |
| * Round a double value to the nearest integer according to the |
| * given mode. |
| * @param a the absolute value of the number to be rounded |
| * @param mode a BigDecimal rounding mode |
| * @param isNegative true if the number to be rounded is negative |
| * @return the absolute value of the rounded result |
| */ |
| double DecimalFormat::round(double a, ERoundingMode mode, bool_t isNegative) { |
| switch (mode) { |
| case kRoundCeiling: |
| return isNegative ? uprv_floor(a) : uprv_ceil(a); |
| case kRoundFloor: |
| return isNegative ? uprv_ceil(a) : uprv_floor(a); |
| case kRoundDown: |
| return uprv_floor(a); |
| case kRoundUp: |
| return uprv_ceil(a); |
| case kRoundHalfEven: |
| { |
| double f = uprv_floor(a); |
| if ((a - f) != 0.5) { |
| return uprv_floor(a + 0.5); |
| } |
| double g = f / 2.0; |
| return (g == uprv_floor(g)) ? f : (f + 1.0); |
| } |
| case kRoundHalfDown: |
| return ((a - uprv_floor(a)) <= 0.5) ? uprv_floor(a) : uprv_ceil(a); |
| case kRoundHalfUp: |
| return ((a - uprv_floor(a)) < 0.5) ? uprv_floor(a) : uprv_ceil(a); |
| } |
| return 1.0; |
| } |
| |
| UnicodeString& |
| DecimalFormat::format( const Formattable& obj, |
| UnicodeString& result, |
| FieldPosition& fieldPosition, |
| UErrorCode& status) const |
| { |
| return NumberFormat::format(obj, result, fieldPosition, status); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| /** |
| * Complete the formatting of a finite number. On entry, the fDigitList must |
| * be filled in with the correct digits. |
| */ |
| UnicodeString& |
| DecimalFormat::subformat(UnicodeString& result, |
| FieldPosition& fieldPosition, |
| bool_t isNegative, |
| bool_t isInteger) const |
| { |
| // Gets the localized zero Unicode character. |
| UChar zero = fSymbols->getZeroDigit(); |
| int32_t zeroDelta = zero - '0'; // '0' is the DigitList representation of zero |
| UChar grouping = fSymbols->getGroupingSeparator(); |
| UChar decimal = fIsCurrencyFormat ? |
| fSymbols->getMonetaryDecimalSeparator() : |
| fSymbols->getDecimalSeparator(); |
| int32_t maxIntDig = getMaximumIntegerDigits(); |
| int32_t minIntDig = getMinimumIntegerDigits(); |
| |
| /* Per bug 4147706, DecimalFormat must respect the sign of numbers which |
| * format as zero. This allows sensible computations and preserves |
| * relations such as signum(1/x) = signum(x), where x is +Infinity or |
| * -Infinity. Prior to this fix, we always formatted zero values as if |
| * they were positive. Liu 7/6/98. |
| */ |
| if (fDigitList->isZero()) |
| { |
| fDigitList->fDecimalAt = fDigitList->fCount = 0; // Normalize |
| } |
| |
| // Appends the prefix. |
| result += (isNegative ? fNegativePrefix : fPositivePrefix); |
| |
| if (fUseExponentialNotation) |
| { |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| { |
| fieldPosition.setBeginIndex(result.length()); |
| fieldPosition.setEndIndex(-1); |
| } |
| else if (fieldPosition.getField() == NumberFormat::kFractionField) |
| { |
| fieldPosition.setBeginIndex(-1); |
| } |
| |
| // Minimum integer digits are handled in exponential format by |
| // adjusting the exponent. For example, 0.01234 with 3 minimum |
| // integer digits is "123.4E-4". |
| |
| // Maximum integer digits are interpreted as indicating the |
| // repeating range. This is useful for engineering notation, in |
| // which the exponent is restricted to a multiple of 3. For |
| // example, 0.01234 with 3 maximum integer digits is "12.34e-3". |
| // If maximum integer digits are defined and are larger than |
| // minimum integer digits, then minimum integer digits are |
| // ignored. |
| int32_t exponent = fDigitList->fDecimalAt; |
| if (maxIntDig > 1 && maxIntDig != minIntDig) { |
| // A exponent increment is defined; adjust to it. |
| exponent = (exponent > 0) ? (exponent - 1) / maxIntDig |
| : (exponent / maxIntDig) - 1; |
| exponent *= maxIntDig; |
| } else { |
| // No exponent increment is defined; use minimum integer digits. |
| // If none is specified, as in "#E0", generate 1 integer digit. |
| exponent -= (minIntDig > 0 || getMinimumFractionDigits() > 0) |
| ? minIntDig : 1; |
| } |
| |
| // We now output a minimum number of digits, and more if there |
| // are more digits, up to the maximum number of digits. We |
| // place the decimal point after the "integer" digits, which |
| // are the first (decimalAt - exponent) digits. |
| int32_t minimumDigits = minIntDig + getMinimumFractionDigits(); |
| // The number of integer digits is handled specially if the number |
| // is zero, since then there may be no digits. |
| int32_t integerDigits = fDigitList->isZero() ? minIntDig : |
| fDigitList->fDecimalAt - exponent; |
| int32_t totalDigits = fDigitList->fCount; |
| if (minimumDigits > totalDigits) totalDigits = minimumDigits; |
| if (integerDigits > totalDigits) totalDigits = integerDigits; |
| |
| // totalDigits records total number of digits needs to be processed |
| int32_t i; |
| for (i=0; i<totalDigits; ++i) |
| { |
| if (i == integerDigits) |
| { |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setEndIndex(result.length()); |
| |
| result += (decimal); |
| |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kFractionField) |
| fieldPosition.setBeginIndex(result.length()); |
| } |
| // Restores the digit character or pads the buffer with zeros. |
| UChar c = ((i < fDigitList->fCount) ? |
| (UChar)(fDigitList->fDigits[i] + zeroDelta) : |
| zero); |
| result += c; |
| } |
| |
| // Record field information |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| { |
| if (fieldPosition.getEndIndex() < 0) |
| fieldPosition.setEndIndex(result.length()); |
| } |
| else if (fieldPosition.getField() == NumberFormat::kFractionField) |
| { |
| if (fieldPosition.getBeginIndex() < 0) |
| fieldPosition.setBeginIndex(result.length()); |
| fieldPosition.setEndIndex(result.length()); |
| } |
| |
| // The exponent is output using the pattern-specified minimum |
| // exponent digits. There is no maximum limit to the exponent |
| // digits, since truncating the exponent would result in an |
| // unacceptable inaccuracy. |
| result += fSymbols->getExponentialSymbol(); |
| |
| // For zero values, we force the exponent to zero. We |
| // must do this here, and not earlier, because the value |
| // is used to determine integer digit count above. |
| if (fDigitList->isZero()) exponent = 0; |
| |
| bool_t negativeExponent = exponent < 0; |
| if (negativeExponent) { |
| exponent = -exponent; |
| result += fSymbols->getMinusSign(); |
| } else if (fExponentSignAlwaysShown) { |
| result += fSymbols->getPlusSign(); |
| } |
| if (negativeExponent) exponent = -exponent; |
| DecimalFormat* non_const = (DecimalFormat*)this; |
| non_const->fDigitList->set(exponent); |
| for (i=fDigitList->fDecimalAt; i<fMinExponentDigits; ++i) |
| result += (zero); |
| for (i=0; i<fDigitList->fDecimalAt; ++i) |
| { |
| UChar c = ((i < fDigitList->fCount) ? |
| (UChar)(fDigitList->fDigits[i] + zeroDelta) : zero); |
| result += c; |
| } |
| } |
| else // Not using exponential notation |
| { |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setBeginIndex(result.length()); |
| |
| // Output the integer portion. Here 'count' is the total |
| // number of integer digits we will display, including both |
| // leading zeros required to satisfy getMinimumIntegerDigits, |
| // and actual digits present in the number. |
| int32_t count = minIntDig; |
| int32_t digitIndex = 0; // Index into fDigitList->fDigits[] |
| if (fDigitList->fDecimalAt > 0 && count < fDigitList->fDecimalAt) |
| count = fDigitList->fDecimalAt; |
| |
| // Handle the case where getMaximumIntegerDigits() is smaller |
| // than the real number of integer digits. If this is so, we |
| // output the least significant max integer digits. For example, |
| // the value 1997 printed with 2 max integer digits is just "97". |
| |
| if (count > maxIntDig) |
| { |
| count = maxIntDig; |
| digitIndex = fDigitList->fDecimalAt - count; |
| } |
| |
| int32_t sizeBeforeIntegerPart = result.length(); |
| |
| int32_t i; |
| for (i=count-1; i>=0; --i) |
| { |
| if (i < fDigitList->fDecimalAt && digitIndex < fDigitList->fCount) |
| { |
| // Output a real digit |
| result += ((UChar)(fDigitList->fDigits[digitIndex++] + zeroDelta)); |
| } |
| else |
| { |
| // Output a leading zero |
| result += (zero); |
| } |
| |
| // Output grouping separator if necessary. Don't output a |
| // grouping separator if i==0 though; that's at the end of |
| // the integer part. |
| if (isGroupingUsed() && i>0 && (fGroupingSize != 0) && (i % fGroupingSize == 0)) |
| { |
| result += (grouping); |
| } |
| } |
| |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kIntegerField) |
| fieldPosition.setEndIndex(result.length()); |
| |
| // Determine whether or not there are any printable fractional |
| // digits. If we've used up the digits we know there aren't. |
| bool_t fractionPresent = (getMinimumFractionDigits() > 0) || |
| (!isInteger && digitIndex < fDigitList->fCount); |
| |
| // If there is no fraction present, and we haven't printed any |
| // integer digits, then print a zero. Otherwise we won't print |
| // _any_ digits, and we won't be able to parse this string. |
| if (!fractionPresent && result.length() == sizeBeforeIntegerPart) |
| result += (zero); |
| |
| // Output the decimal separator if we always do so. |
| if (fDecimalSeparatorAlwaysShown || fractionPresent) |
| result += (decimal); |
| |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kFractionField) |
| fieldPosition.setBeginIndex(result.length()); |
| |
| for (i=0; i < getMaximumFractionDigits(); ++i) |
| { |
| // Here is where we escape from the loop. We escape if we've output |
| // the maximum fraction digits (specified in the for expression above). |
| // We also stop when we've output the minimum digits and either: |
| // we have an integer, so there is no fractional stuff to display, |
| // or we're out of significant digits. |
| if (i >= getMinimumFractionDigits() && |
| (isInteger || digitIndex >= fDigitList->fCount)) |
| break; |
| |
| // Output leading fractional zeros. These are zeros that come after |
| // the decimal but before any significant digits. These are only |
| // output if abs(number being formatted) < 1.0. |
| if (-1-i > (fDigitList->fDecimalAt-1)) |
| { |
| result += (zero); |
| continue; |
| } |
| |
| // Output a digit, if we have any precision left, or a |
| // zero if we don't. We don't want to output noise digits. |
| if (!isInteger && digitIndex < fDigitList->fCount) |
| { |
| result += ((UChar)(fDigitList->fDigits[digitIndex++] + zeroDelta)); |
| } |
| else |
| { |
| result += (zero); |
| } |
| } |
| |
| // Record field information for caller. |
| if (fieldPosition.getField() == NumberFormat::kFractionField) |
| fieldPosition.setEndIndex(result.length()); |
| } |
| |
| result += (isNegative ? fNegativeSuffix : fPositiveSuffix); |
| |
| addPadding(result, TRUE, isNegative); |
| return result; |
| } |
| |
| /** |
| * Inserts the character fPad as needed to expand result to fFormatWidth. |
| * @param result the string to be padded |
| * @param hasAffixes if true, padding is positioned appropriately before or |
| * after affixes. If false, then isNegative is ignored, and there are only |
| * two effective pad positions: kPadBeforePrefix/kPadAfterPrefix and |
| * kPadBeforeSuffix/kPadAfterSuffix. |
| * @param isNegative must be true if result contains a formatted negative |
| * number, and false otherwise. Ignored if hasAffixes is false. |
| */ |
| void DecimalFormat::addPadding(UnicodeString& result, bool_t hasAffixes, |
| bool_t isNegative) const { |
| if (fFormatWidth > 0) { |
| int32_t len = fFormatWidth - result.length(); |
| if (len > 0) { |
| UChar* padding = (UChar*) uprv_malloc(sizeof(UChar) * len); |
| for (int32_t i=0; i<len; ++i) { |
| padding[i] = fPad; |
| } |
| switch (fPadPosition) { |
| case kPadAfterPrefix: |
| if (hasAffixes) { |
| result.insert(isNegative ? fNegativePrefix.length() |
| : fPositivePrefix.length(), |
| padding, len); |
| break; |
| } // else fall through to next case |
| case kPadBeforePrefix: |
| result.insert(0, padding, len); |
| break; |
| case kPadBeforeSuffix: |
| if (hasAffixes) { |
| result.insert(result.length() - |
| (isNegative ? fNegativeSuffix.length() |
| : fPositiveSuffix.length()), |
| padding, len); |
| break; |
| } // else fall through to next case |
| case kPadAfterSuffix: |
| result += padding; |
| break; |
| } |
| uprv_free(padding); |
| } |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| DecimalFormat::parse(const UnicodeString& text, |
| Formattable& result, |
| UErrorCode& status) const |
| { |
| NumberFormat::parse(text, result, status); |
| } |
| |
| const int32_t DecimalFormat::fgStatusInfinite = 0; |
| const int32_t DecimalFormat::fgStatusPositive = 1; |
| const int32_t DecimalFormat::fgStatusLength = 2; |
| |
| void |
| DecimalFormat::parse(const UnicodeString& text, |
| Formattable& result, |
| ParsePosition& parsePosition) const |
| { |
| // Skip padding characters, if any |
| int32_t backup = parsePosition.getIndex(); |
| int32_t i = backup; |
| if (fFormatWidth > 0) { |
| while (i < text.length() && text[(UTextOffset) i] == fPad) { |
| ++i; |
| } |
| parsePosition.setIndex(i); |
| } |
| |
| // special case NaN |
| UnicodeString nan; |
| fSymbols->getNaN(nan); |
| // If the text is composed of the representation of NaN, returns NaN. |
| if (text.compare(parsePosition.getIndex(), nan.length(), nan, |
| 0, nan.length()) == 0) { |
| parsePosition.setIndex(parsePosition.getIndex() + nan.length()); |
| result.setDouble(uprv_getNaN()); |
| return; |
| } |
| |
| // status is used to record whether a number is |
| // infinite or positive. |
| bool_t status[fgStatusLength]; |
| |
| if (!subparse(text, parsePosition, *fDigitList, FALSE, status)) { |
| parsePosition.setIndex(backup); |
| return; |
| } else if (fFormatWidth < 0) { |
| i = parsePosition.getIndex(); |
| while (i < text.length() && text[(UTextOffset) i] == fPad) { |
| ++i; |
| } |
| parsePosition.setIndex(i); |
| } |
| |
| // Handle infinity |
| if (status[fgStatusInfinite]) { |
| double inf = uprv_getInfinity(); |
| result.setDouble(status[fgStatusPositive] ? inf : -inf); |
| return; |
| } |
| |
| // Do as much of the multiplier conversion as possible without |
| // losing accuracy. |
| int32_t mult = fMultiplier; // Don't modify this.multiplier |
| while (mult % 10 == 0) { |
| --fDigitList->fDecimalAt; |
| mult /= 10; |
| } |
| |
| // Handle integral values |
| if (fDigitList->fitsIntoLong(status[fgStatusPositive], |
| isParseIntegerOnly())) { |
| int32_t n = fDigitList->getLong(); |
| if (n % mult == 0) { |
| n /= mult; |
| result.setLong((status[fgStatusPositive] == n>=0) ? n : -n); |
| return; |
| } |
| } |
| |
| // Handle non-integral values |
| double a = fDigitList->getDouble(); |
| if (mult != 1) { |
| a /= mult; |
| } |
| result.setDouble(status[fgStatusPositive] ? a : -a); |
| } |
| |
| /** |
| * Parse the given text into a number. The text is parsed beginning at |
| * parsePosition, until an unparseable character is seen. |
| * @param text The string to parse. |
| * @param parsePosition The position at which to being parsing. Upon |
| * return, the first unparseable character. |
| * @param digits The DigitList to set to the parsed value. |
| * @param isExponent If true, parse an exponent. This means no |
| * infinite values and integer only. |
| * @param status Upon return contains boolean status flags indicating |
| * whether the value was infinite and whether it was positive. |
| */ |
| bool_t DecimalFormat::subparse(const UnicodeString& text, ParsePosition& parsePosition, |
| DigitList& digits, bool_t isExponent, |
| bool_t* status) const |
| { |
| int32_t position = parsePosition.getIndex(); |
| int32_t oldStart = parsePosition.getIndex(); |
| int32_t backup; |
| |
| // check for positivePrefix; take longest |
| bool_t gotPositive = text.compare(position,fPositivePrefix.length(),fPositivePrefix,0, |
| fPositivePrefix.length()) == 0; |
| bool_t gotNegative = text.compare(position,fNegativePrefix.length(),fNegativePrefix,0, |
| fNegativePrefix.length()) == 0; |
| // If the number is positive and negative at the same time, |
| // 1. the number is positive if the positive prefix is longer |
| // 2. the number is negative if the negative prefix is longer |
| if (gotPositive && gotNegative) { |
| if (fPositivePrefix.length() > fNegativePrefix.length()) |
| gotNegative = FALSE; |
| else if (fPositivePrefix.length() < fNegativePrefix.length()) |
| gotPositive = FALSE; |
| } |
| if(gotPositive) |
| position += fPositivePrefix.length(); |
| else if(gotNegative) |
| position += fNegativePrefix.length(); |
| else { |
| parsePosition.setErrorIndex(position); |
| return FALSE; |
| } |
| // process digits or Inf, find decimal position |
| status[fgStatusInfinite] = FALSE; |
| UnicodeString inf; |
| fSymbols->getInfinity(inf); |
| if (!isExponent && text.compare(position,inf.length(),inf,0, |
| inf.length()) == 0) |
| { |
| // Found a infinite number. |
| position += inf.length(); |
| status[fgStatusInfinite] = TRUE; |
| } else { |
| // We now have a string of digits, possibly with grouping symbols, |
| // and decimal points. We want to process these into a DigitList. |
| // We don't want to put a bunch of leading zeros into the DigitList |
| // though, so we keep track of the location of the decimal point, |
| // put only significant digits into the DigitList, and adjust the |
| // exponent as needed. |
| |
| digits.fDecimalAt = digits.fCount = 0; |
| UChar zero = fSymbols->getZeroDigit(); |
| //UChar nine = (UChar)(zero + 9); |
| //int32_t zeroDelta = '0' - zero; |
| UChar decimal = fIsCurrencyFormat ? |
| fSymbols->getMonetaryDecimalSeparator() : fSymbols->getDecimalSeparator(); |
| UChar grouping = fSymbols->getGroupingSeparator(); |
| UChar exponentChar = fSymbols->getExponentialSymbol(); |
| bool_t sawDecimal = FALSE; |
| bool_t sawExponent = FALSE; |
| bool_t sawDigit= FALSE; |
| int32_t exponent = 0; // Set to the exponent value, if any |
| |
| // We have to track digitCount ourselves, because digits.fCount will |
| // pin when the maximum allowable digits is reached. |
| int32_t digitCount = 0; |
| |
| backup = -1; |
| for (; position < text.length(); ++position) |
| { |
| UChar ch = text[(UTextOffset)position]; |
| |
| /* We recognize all digit ranges, not only the Latin digit range |
| * '0'..'9'. We do so by using the Character.digit() method, |
| * which converts a valid Unicode digit to the range 0..9. |
| * |
| * The character 'ch' may be a digit. If so, place its value |
| * from 0 to 9 in 'digit'. First try using the locale digit, |
| * which may or MAY NOT be a standard Unicode digit range. If |
| * this fails, try using the standard Unicode digit ranges by |
| * calling Character.digit(). If this also fails, digit will |
| * have a value outside the range 0..9. |
| */ |
| int32_t digit = ch - zero; |
| if (digit < 0 || digit > 9) digit = Unicode::digitValue(ch); |
| |
| if (digit == 0) |
| { |
| // Cancel out backup setting (see grouping handler below) |
| backup = -1; // Do this BEFORE continue statement below!!! |
| sawDigit = TRUE; |
| |
| // Handle leading zeros |
| if (digits.fCount == 0) |
| { |
| // Ignore leading zeros in integer part of number. |
| if (!sawDecimal) continue; |
| |
| // If we have seen the decimal, but no significant digits yet, |
| // then we account for leading zeros by decrementing the |
| // digits.fDecimalAt into negative values. |
| --digits.fDecimalAt; |
| } |
| else |
| { |
| // output a regular zero digit. |
| ++digitCount; |
| digits.append((char)(digit + '0')); |
| } |
| } |
| else if (digit > 0 && digit <= 9) |
| { |
| sawDigit = TRUE; |
| // output a regular non-zero digit. |
| ++digitCount; |
| digits.append((char)(digit + '0')); |
| |
| // Cancel out backup setting (see grouping handler below) |
| backup = -1; |
| } |
| else if (!isExponent && ch == decimal) |
| { |
| // If we're only parsing integers, or if we ALREADY saw the |
| // decimal, then don't parse this one. |
| if (isParseIntegerOnly() || sawDecimal) break; |
| digits.fDecimalAt = digitCount; // Not digits.fCount! |
| sawDecimal = TRUE; |
| } |
| else if (!isExponent && ch == grouping && isGroupingUsed()) |
| { |
| // Ignore grouping characters, if we are using them, but require |
| // that they be followed by a digit. Otherwise we backup and |
| // reprocess them. |
| backup = position; |
| } |
| else if (!isExponent && ch == exponentChar && !sawExponent) |
| { |
| // Parse sign, if present |
| bool_t negExp = FALSE; |
| int32_t pos = position + 1; // position + exponentSep.length(); |
| if (pos < text.length()) { |
| ch = text[(UTextOffset) pos]; |
| if (ch == fSymbols->getPlusSign()) { |
| ++pos; |
| } else if (ch == fSymbols->getMinusSign()) { |
| ++pos; |
| negExp = TRUE; |
| } |
| } |
| |
| DigitList exponentDigits; |
| exponentDigits.fCount = 0; |
| while (pos < text.length()) { |
| digit = text[(UTextOffset) pos] - zero; |
| //~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~ |
| // TEMPORARY WORKAROUND |
| //~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~ |
| // The following code is disabled pending a fix to |
| // Unicode::digitValue(). Currently, |
| // Unicode::digitValue(']') returns 0, when it should |
| // return -1. Liu 6/15/99 |
| //~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~ |
| // TEMPORARY WORKAROUND |
| //~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~~*~ |
| |
| // if (digit < 0 || digit > 9) { |
| // digit = Unicode::digitValue(ch); |
| // } |
| if (digit >= 0 && digit <= 9) { |
| exponentDigits.append((char)(digit + '0')); |
| ++pos; |
| } else { |
| break; |
| } |
| } |
| |
| if (exponentDigits.fCount > 0) { |
| exponentDigits.fDecimalAt = exponentDigits.fCount; |
| exponent = exponentDigits.getLong(); |
| if (negExp) { |
| exponent = -exponent; |
| } |
| position = pos; // Advance past the exponent |
| sawExponent = TRUE; |
| } |
| |
| break; // Whether we fail or succeed, we exit this loop |
| } |
| else break; |
| } |
| |
| if (backup != -1) position = backup; |
| |
| // If there was no decimal point we have an integer |
| if (!sawDecimal) digits.fDecimalAt = digitCount; // Not digits.fCount! |
| |
| // Adjust for exponent, if any |
| digits.fDecimalAt += exponent; |
| |
| // If none of the text string was recognized. For example, parse |
| // "x" with pattern "#0.00" (return index and error index both 0) |
| // parse "$" with pattern "$#0.00". (return index 0 and error index |
| // 1). |
| if (!sawDigit && digitCount == 0) { |
| parsePosition.setIndex(oldStart); |
| parsePosition.setErrorIndex(oldStart); |
| return FALSE; |
| } |
| } |
| |
| // check for positiveSuffix |
| if (gotPositive) |
| gotPositive = text.compare(position,fPositiveSuffix.length(),fPositiveSuffix,0, |
| fPositiveSuffix.length()) == 0; |
| if (gotNegative) |
| gotNegative = text.compare(position,fNegativeSuffix.length(),fNegativeSuffix,0, |
| fNegativeSuffix.length()) == 0; |
| |
| // if both match, take longest |
| if (gotPositive && gotNegative) { |
| if (fPositiveSuffix.length() > fNegativeSuffix.length()) |
| gotNegative = FALSE; |
| else if (fPositiveSuffix.length() < fNegativeSuffix.length()) |
| gotPositive = FALSE; |
| } |
| |
| // fail if neither or both |
| if (gotPositive == gotNegative) { |
| parsePosition.setErrorIndex(position); |
| return FALSE; |
| } |
| |
| parsePosition.setIndex(position + |
| (gotPositive ? fPositiveSuffix.length() : |
| fNegativeSuffix.length())); // mark success! |
| |
| status[fgStatusPositive] = gotPositive; |
| |
| if(parsePosition.getIndex() == oldStart) { |
| parsePosition.setErrorIndex(position); |
| return FALSE; |
| } |
| return TRUE; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the pointer to the localized decimal format symbols |
| |
| const DecimalFormatSymbols* |
| DecimalFormat::getDecimalFormatSymbols() const |
| { |
| return fSymbols; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // De-owning the current localized symbols and adopt the new symbols. |
| |
| void |
| DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) |
| { |
| if (fSymbols != NULL) |
| delete fSymbols; |
| |
| fSymbols = symbolsToAdopt; |
| } |
| //------------------------------------------------------------------------------ |
| // Setting the symbols is equlivalent to adopting a newly created localized |
| // symbols. |
| |
| void |
| DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) |
| { |
| adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); |
| expandAffixes(); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the positive prefix of the number pattern. |
| |
| UnicodeString& |
| DecimalFormat::getPositivePrefix(UnicodeString& result) const |
| { |
| result = fPositivePrefix; |
| return result; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Sets the positive prefix of the number pattern. |
| |
| void |
| DecimalFormat::setPositivePrefix(const UnicodeString& newValue) |
| { |
| fPositivePrefix = newValue; |
| delete fPosPrefixPattern; |
| fPosPrefixPattern = 0; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the negative prefix of the number pattern. |
| |
| UnicodeString& |
| DecimalFormat::getNegativePrefix(UnicodeString& result) const |
| { |
| result = fNegativePrefix; |
| return result; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the negative prefix of the number pattern. |
| |
| void |
| DecimalFormat::setNegativePrefix(const UnicodeString& newValue) |
| { |
| fNegativePrefix = newValue; |
| delete fNegPrefixPattern; |
| fNegPrefixPattern = 0; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the positive suffix of the number pattern. |
| |
| UnicodeString& |
| DecimalFormat::getPositiveSuffix(UnicodeString& result) const |
| { |
| result = fPositiveSuffix; |
| return result; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Sets the positive suffix of the number pattern. |
| |
| void |
| DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) |
| { |
| fPositiveSuffix = newValue; |
| delete fPosSuffixPattern; |
| fPosSuffixPattern = 0; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the negative suffix of the number pattern. |
| |
| UnicodeString& |
| DecimalFormat::getNegativeSuffix(UnicodeString& result) const |
| { |
| result = fNegativeSuffix; |
| return result; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Sets the negative suffix of the number pattern. |
| |
| void |
| DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) |
| { |
| fNegativeSuffix = newValue; |
| delete fNegSuffixPattern; |
| fNegSuffixPattern = 0; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the multiplier of the number pattern. |
| |
| int32_t DecimalFormat::getMultiplier() const |
| { |
| return fMultiplier; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Sets the multiplier of the number pattern. |
| |
| void |
| DecimalFormat::setMultiplier(int32_t newValue) |
| { |
| // We should really take a UErrorCode and disallow values <= 0 - liu |
| fMultiplier = newValue; |
| } |
| |
| /** |
| * Get the rounding increment. |
| * @return A positive rounding increment, or 0.0 if rounding |
| * is not in effect. |
| * @see #setRoundingIncrement |
| * @see #getRoundingMode |
| * @see #setRoundingMode |
| */ |
| double DecimalFormat::getRoundingIncrement() { |
| return fRoundingDouble; |
| } |
| |
| /** |
| * Set the rounding increment. This method also controls whether |
| * rounding is enabled. |
| * @param newValue A positive rounding increment, or 0.0 to disable rounding. |
| * Negative increments are equivalent to 0.0. |
| * @see #getRoundingIncrement |
| * @see #getRoundingMode |
| * @see #setRoundingMode |
| */ |
| void DecimalFormat::setRoundingIncrement(double newValue) { |
| if (newValue > 0.0) { |
| if (fRoundingIncrement == NULL) { |
| fRoundingIncrement = new DigitList(); |
| } |
| fRoundingIncrement->set((long)newValue); |
| fRoundingDouble = newValue; |
| } else { |
| delete fRoundingIncrement; |
| fRoundingIncrement = NULL; |
| fRoundingDouble = 0.0; |
| } |
| } |
| |
| /** |
| * Get the rounding mode. |
| * @return A rounding mode |
| * @see #setRoundingIncrement |
| * @see #getRoundingIncrement |
| * @see #setRoundingMode |
| */ |
| DecimalFormat::ERoundingMode DecimalFormat::getRoundingMode() { |
| return fRoundingMode; |
| } |
| |
| /** |
| * Set the rounding mode. This has no effect unless the rounding |
| * increment is greater than zero. |
| * @param roundingMode A rounding mode |
| * @see #setRoundingIncrement |
| * @see #getRoundingIncrement |
| * @see #getRoundingMode |
| */ |
| void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { |
| fRoundingMode = roundingMode; |
| } |
| |
| /** |
| * Get the width to which the output of <code>format()</code> is padded. |
| * @return the format width, or zero if no padding is in effect |
| * @see #setFormatWidth |
| * @see #getPadCharacter |
| * @see #setPadCharacter |
| * @see #getPadPosition |
| * @see #setPadPosition |
| */ |
| int32_t DecimalFormat::getFormatWidth() { |
| return fFormatWidth; |
| } |
| |
| /** |
| * Set the width to which the output of <code>format()</code> is padded. |
| * This method also controls whether padding is enabled. |
| * @param width the width to which to pad the result of |
| * <code>format()</code>, or zero to disable padding. A negative |
| * width is equivalent to 0. |
| * @see #getFormatWidth |
| * @see #getPadCharacter |
| * @see #setPadCharacter |
| * @see #getPadPosition |
| * @see #setPadPosition |
| */ |
| void DecimalFormat::setFormatWidth(int32_t width) { |
| fFormatWidth = (width > 0) ? width : 0; |
| } |
| |
| /** |
| * Get the character used to pad to the format width. The default is ' '. |
| * @return the pad character |
| * @see #setFormatWidth |
| * @see #getFormatWidth |
| * @see #setPadCharacter |
| * @see #getPadPosition |
| * @see #setPadPosition |
| */ |
| UChar DecimalFormat::getPadCharacter() { |
| return fPad; |
| } |
| |
| /** |
| * Set the character used to pad to the format width. This has no effect |
| * unless padding is enabled. |
| * @param padChar the pad character |
| * @see #setFormatWidth |
| * @see #getFormatWidth |
| * @see #getPadCharacter |
| * @see #getPadPosition |
| * @see #setPadPosition |
| */ |
| void DecimalFormat::setPadCharacter(UChar padChar) { |
| fPad = padChar; |
| } |
| |
| /** |
| * Get the position at which padding will take place. This is the location |
| * at which padding will be inserted if the result of <code>format()</code> |
| * is shorter than the format width. |
| * @return the pad position, one of <code>kPadBeforePrefix</code>, |
| * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or |
| * <code>kPadAfterSuffix</code>. |
| * @see #setFormatWidth |
| * @see #getFormatWidth |
| * @see #setPadCharacter |
| * @see #getPadCharacter |
| * @see #setPadPosition |
| * @see #kPadBeforePrefix |
| * @see #kPadAfterPrefix |
| * @see #kPadBeforeSuffix |
| * @see #kPadAfterSuffix |
| */ |
| DecimalFormat::EPadPosition DecimalFormat::getPadPosition() { |
| return fPadPosition; |
| } |
| |
| /** |
| * <strong><font face=helvetica color=red>NEW</font></strong> |
| * Set the position at which padding will take place. This is the location |
| * at which padding will be inserted if the result of <code>format()</code> |
| * is shorter than the format width. This has no effect unless padding is |
| * enabled. |
| * @param padPos the pad position, one of <code>kPadBeforePrefix</code>, |
| * <code>kPadAfterPrefix</code>, <code>kPadBeforeSuffix</code>, or |
| * <code>kPadAfterSuffix</code>. |
| * @see #setFormatWidth |
| * @see #getFormatWidth |
| * @see #setPadCharacter |
| * @see #getPadCharacter |
| * @see #getPadPosition |
| * @see #kPadBeforePrefix |
| * @see #kPadAfterPrefix |
| * @see #kPadBeforeSuffix |
| * @see #kPadAfterSuffix |
| */ |
| void DecimalFormat::setPadPosition(EPadPosition padPos) { |
| fPadPosition = padPos; |
| } |
| |
| /** |
| * Return whether or not scientific notation is used. |
| * @return TRUE if this object formats and parses scientific notation |
| * @see #setScientificNotation |
| * @see #getMinimumExponentDigits |
| * @see #setMinimumExponentDigits |
| * @see #isExponentSignAlwaysShown |
| * @see #setExponentSignAlwaysShown |
| */ |
| bool_t DecimalFormat::isScientificNotation() { |
| return fUseExponentialNotation; |
| } |
| |
| /** |
| * Set whether or not scientific notation is used. |
| * @param useScientific TRUE if this object formats and parses scientific |
| * notation |
| * @see #isScientificNotation |
| * @see #getMinimumExponentDigits |
| * @see #setMinimumExponentDigits |
| * @see #isExponentSignAlwaysShown |
| * @see #setExponentSignAlwaysShown |
| */ |
| void DecimalFormat::setScientificNotation(bool_t useScientific) { |
| fUseExponentialNotation = useScientific; |
| if (fUseExponentialNotation && fMinExponentDigits < 1) { |
| fMinExponentDigits = 1; |
| } |
| } |
| |
| /** |
| * Return the minimum exponent digits that will be shown. |
| * @return the minimum exponent digits that will be shown |
| * @see #setScientificNotation |
| * @see #isScientificNotation |
| * @see #setMinimumExponentDigits |
| * @see #isExponentSignAlwaysShown |
| * @see #setExponentSignAlwaysShown |
| */ |
| int8_t DecimalFormat::getMinimumExponentDigits() { |
| return fMinExponentDigits; |
| } |
| |
| /** |
| * Set the minimum exponent digits that will be shown. This has no |
| * effect unless scientific notation is in use. |
| * @param minExpDig a value >= 1 indicating the fewest exponent digits |
| * that will be shown. Values less than 1 will be treated as 1. |
| * @see #setScientificNotation |
| * @see #isScientificNotation |
| * @see #getMinimumExponentDigits |
| * @see #isExponentSignAlwaysShown |
| * @see #setExponentSignAlwaysShown |
| */ |
| void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { |
| fMinExponentDigits = (minExpDig > 0) ? minExpDig : 1; |
| } |
| |
| /** |
| * Return whether the exponent sign is always shown. |
| * @return TRUE if the exponent is always prefixed with either the |
| * localized minus sign or the localized plus sign, false if only negative |
| * exponents are prefixed with the localized minus sign. |
| * @see #setScientificNotation |
| * @see #isScientificNotation |
| * @see #setMinimumExponentDigits |
| * @see #getMinimumExponentDigits |
| * @see #setExponentSignAlwaysShown |
| */ |
| bool_t DecimalFormat::isExponentSignAlwaysShown() { |
| return fExponentSignAlwaysShown; |
| } |
| |
| /** |
| * Set whether the exponent sign is always shown. This has no effect |
| * unless scientific notation is in use. |
| * @param expSignAlways TRUE if the exponent is always prefixed with either |
| * the localized minus sign or the localized plus sign, false if only |
| * negative exponents are prefixed with the localized minus sign. |
| * @see #setScientificNotation |
| * @see #isScientificNotation |
| * @see #setMinimumExponentDigits |
| * @see #getMinimumExponentDigits |
| * @see #isExponentSignAlwaysShown |
| */ |
| void DecimalFormat::setExponentSignAlwaysShown(bool_t expSignAlways) { |
| fExponentSignAlwaysShown = expSignAlways; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the grouping size of the number pattern. For example, thousand or 10 |
| // thousand groupings. |
| |
| int32_t |
| DecimalFormat::getGroupingSize() const |
| { |
| return fGroupingSize; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Gets the grouping size of the number pattern. |
| |
| void |
| DecimalFormat::setGroupingSize(int32_t newValue) |
| { |
| fGroupingSize = newValue; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Checks if to show the decimal separator. |
| |
| bool_t |
| DecimalFormat::isDecimalSeparatorAlwaysShown() const |
| { |
| return fDecimalSeparatorAlwaysShown; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Sets to always show the decimal separator. |
| |
| void |
| DecimalFormat::setDecimalSeparatorAlwaysShown(bool_t newValue) |
| { |
| fDecimalSeparatorAlwaysShown = newValue; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Emits the pattern of this DecimalFormat instance. |
| |
| UnicodeString& |
| DecimalFormat::toPattern(UnicodeString& result) const |
| { |
| return toPattern(result, FALSE); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Emits the localized pattern this DecimalFormat instance. |
| |
| UnicodeString& |
| DecimalFormat::toLocalizedPattern(UnicodeString& result) const |
| { |
| return toPattern(result, TRUE); |
| } |
| |
| //------------------------------------------------------------------------------ |
| /** |
| * Expand the affix pattern strings into the expanded affix strings. If any |
| * affix pattern string is null, do not expand it. This method should be |
| * called any time the symbols or the affix patterns change in order to keep |
| * the expanded affix strings up to date. |
| */ |
| void DecimalFormat::expandAffixes(void) { |
| if (fPosPrefixPattern != 0) { |
| expandAffix(*fPosPrefixPattern, fPositivePrefix); |
| } |
| if (fPosSuffixPattern != 0) { |
| expandAffix(*fPosSuffixPattern, fPositiveSuffix); |
| } |
| if (fNegPrefixPattern != 0) { |
| expandAffix(*fNegPrefixPattern, fNegativePrefix); |
| } |
| if (fNegSuffixPattern != 0) { |
| expandAffix(*fNegSuffixPattern, fNegativeSuffix); |
| } |
| #ifdef DEBUG |
| UnicodeString s; |
| s.append("[") |
| .append(*fPosPrefixPattern).append("|").append(*fPosSuffixPattern) |
| .append(";") .append(*fNegPrefixPattern).append("|").append(*fNegSuffixPattern) |
| .append("]->[") |
| .append(fPositivePrefix).append("|").append(fPositiveSuffix) |
| .append(";") .append(fNegativePrefix).append("|").append(fNegativeSuffix) |
| .append("]\n"); |
| debugout(s); |
| #endif |
| } |
| |
| /** |
| * Expand an affix pattern into an affix string. All characters in the |
| * pattern are literal unless prefixed by kQuote. The following characters |
| * after kQuote are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, |
| * PATTERN_MINUS, and kCurrencySign. If kCurrencySign is doubled (kQuote + |
| * kCurrencySign + kCurrencySign), it is interpreted as an international |
| * currency sign. Any other character after a kQuote represents itself. |
| * kQuote must be followed by another character; kQuote may not occur by |
| * itself at the end of the pattern. |
| * |
| * @param pattern the non-null, fPossibly empty pattern |
| * @param affix string to receive the expanded equivalent of pattern |
| */ |
| void DecimalFormat::expandAffix(const UnicodeString& pattern, |
| UnicodeString& affix) const { |
| affix.remove(); |
| for (int i=0; i<pattern.length(); ) { |
| UChar c = pattern.charAt(i++); |
| if (c == kQuote) { |
| c = pattern.charAt(i++); |
| switch (c) { |
| case kCurrencySign: |
| { |
| UnicodeString s; |
| if (i<pattern.length() && |
| pattern.charAt(i) == kCurrencySign) { |
| ++i; |
| affix += fSymbols->getInternationalCurrencySymbol(s); |
| } else { |
| affix += fSymbols->getCurrencySymbol(s); |
| } |
| } |
| continue; |
| case kPatternPercent: |
| c = fSymbols->getPercent(); |
| break; |
| case kPatternPerMill: |
| c = fSymbols->getPerMill(); |
| break; |
| case kPatternPlus: |
| c = fSymbols->getPlusSign(); |
| break; |
| case kPatternMinus: |
| c = fSymbols->getMinusSign(); |
| break; |
| } |
| } |
| affix.append(c); |
| } |
| } |
| |
| /** |
| * Appends an affix pattern to the given StringBuffer, quoting special |
| * characters as needed. Uses the internal affix pattern, if that exists, |
| * or the literal affix, if the internal affix pattern is null. The |
| * appended string will generate the same affix pattern (or literal affix) |
| * when passed to toPattern(). |
| * |
| * @param buffer the affix string is appended to this |
| * @param affixPattern a pattern such as fPosPrefixPattern; may be null |
| * @param expAffix a corresponding expanded affix, such as fPositivePrefix. |
| * Ignored unless affixPattern is null. If affixPattern is null, then |
| * expAffix is appended as a literal affix. |
| * @param localized true if the appended pattern should contain localized |
| * pattern characters; otherwise, non-localized pattern chars are appended |
| */ |
| void DecimalFormat::appendAffix(UnicodeString& buffer, |
| const UnicodeString* affixPattern, |
| const UnicodeString& expAffix, |
| bool_t localized) const { |
| if (affixPattern == 0) { |
| appendAffix(buffer, expAffix, localized); |
| } else { |
| int i; |
| for (int pos=0; pos<affixPattern->length(); pos=i) { |
| i = affixPattern->indexOf(kQuote, pos); |
| if (i < 0) { |
| UnicodeString s; |
| affixPattern->extractBetween(pos, affixPattern->length(), s); |
| appendAffix(buffer, s, localized); |
| break; |
| } |
| if (i > pos) { |
| UnicodeString s; |
| affixPattern->extractBetween(pos, i, s); |
| appendAffix(buffer, s, localized); |
| } |
| UChar c = affixPattern->charAt(++i); |
| ++i; |
| if (c == kQuote) { |
| buffer.append(c); |
| // Fall through and append another kQuote below |
| } else if (c == kCurrencySign && |
| i<affixPattern->length() && |
| affixPattern->charAt(i) == kCurrencySign) { |
| ++i; |
| buffer.append(c); |
| // Fall through and append another kCurrencySign below |
| } else if (localized) { |
| switch (c) { |
| case kPatternPercent: |
| c = fSymbols->getPercent(); |
| break; |
| case kPatternPerMill: |
| c = fSymbols->getPerMill(); |
| break; |
| case kPatternPlus: |
| c = fSymbols->getPlusSign(); |
| break; |
| case kPatternMinus: |
| c = fSymbols->getMinusSign(); |
| break; |
| } |
| } |
| buffer.append(c); |
| } |
| } |
| } |
| |
| /** |
| * Append an affix to the given StringBuffer, using quotes if |
| * there are special characters. Single quotes themselves must be |
| * escaped in either case. |
| */ |
| void |
| DecimalFormat::appendAffix( UnicodeString& buffer, |
| const UnicodeString& affix, |
| bool_t localized) const { |
| bool_t needQuote; |
| if(localized) { |
| needQuote = affix.indexOf(fSymbols->getZeroDigit()) >= 0 |
| || affix.indexOf(fSymbols->getGroupingSeparator()) >= 0 |
| || affix.indexOf(fSymbols->getDecimalSeparator()) >= 0 |
| || affix.indexOf(fSymbols->getPercent()) >= 0 |
| || affix.indexOf(fSymbols->getPerMill()) >= 0 |
| || affix.indexOf(fSymbols->getDigit()) >= 0 |
| || affix.indexOf(fSymbols->getPatternSeparator()) >= 0 |
| || affix.indexOf(fSymbols->getPlusSign()) >= 0 |
| || affix.indexOf(fSymbols->getMinusSign()) >= 0 |
| || affix.indexOf(kCurrencySign) >= 0; |
| } |
| else { |
| needQuote = affix.indexOf(kPatternZeroDigit) >= 0 |
| || affix.indexOf(kPatternGroupingSeparator) >= 0 |
| || affix.indexOf(kPatternDecimalSeparator) >= 0 |
| || affix.indexOf(kPatternPercent) >= 0 |
| || affix.indexOf(kPatternPerMill) >= 0 |
| || affix.indexOf(kPatternDigit) >= 0 |
| || affix.indexOf(kPatternSeparator) >= 0 |
| || affix.indexOf(kPatternExponent) >= 0 |
| || affix.indexOf(kPatternPlus) >= 0 |
| || affix.indexOf(kPatternMinus) >= 0 |
| || affix.indexOf(kCurrencySign) >= 0; |
| } |
| if (needQuote) |
| buffer += 0x0027 /*'\''*/; |
| if (affix.indexOf(0x0027 /*'\''*/) < 0) |
| buffer += affix; |
| else { |
| for (int32_t j = 0; j < affix.length(); ++j) { |
| UChar c = affix[j]; |
| buffer += c; |
| if (c == 0x0027 /*'\''*/) buffer += c; |
| } |
| } |
| if (needQuote) buffer += 0x0027 /*'\''*/; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| /* Tell the VC++ compiler not to spew out the warnings about integral size conversion */ |
| #ifdef _WIN32 |
| #pragma warning( disable : 4761 ) |
| #endif |
| |
| UnicodeString& |
| DecimalFormat::toPattern(UnicodeString& result, bool_t localized) const |
| { |
| result.remove(); |
| UChar zero = localized ? fSymbols->getZeroDigit() : kPatternZeroDigit; |
| UChar digit = localized ? fSymbols->getDigit() : kPatternDigit; |
| UChar group = localized ? fSymbols->getGroupingSeparator() |
| : kPatternGroupingSeparator; |
| int32_t i; |
| int32_t roundingDecimalPos = 0; // Pos of decimal in roundingDigits |
| UnicodeString roundingDigits; |
| int32_t padPos = (fFormatWidth > 0) ? fPadPosition : -1; |
| UnicodeString padSpec; |
| if(fFormatWidth > 0) { |
| padSpec.append(localized ? fSymbols->getPadEscape() : kPatternPadEscape). |
| append(fPad); |
| } |
| if(fRoundingIncrement != NULL) { |
| for(i=0; i<fRoundingIncrement->fCount; ++i) { |
| roundingDigits.append(fRoundingIncrement->fDigits[i]); |
| } |
| roundingDecimalPos = fRoundingIncrement->fDecimalAt; |
| } |
| for (int32_t part=0; part<2; ++part) { |
| int32_t partStart = result.length(); |
| if (padPos == kPadBeforePrefix) { |
| result.append(padSpec); |
| } |
| appendAffix(result, |
| (part==0 ? fPosPrefixPattern : fNegPrefixPattern), |
| (part==0 ? fPositivePrefix : fNegativePrefix), |
| localized); |
| if (padPos == kPadAfterPrefix && ! padSpec.empty()) { |
| result.append(padSpec); |
| } |
| int32_t sub0Start = result.length(); |
| int32_t maxIntDig = fUseExponentialNotation ? getMaximumIntegerDigits() : |
| (uprv_max(uprv_max(fGroupingSize, getMinimumIntegerDigits()), |
| roundingDecimalPos) + 1); |
| for (i = maxIntDig; i > 0; --i) { |
| if (isGroupingUsed() && fGroupingSize != 0 |
| && i % fGroupingSize == 0 |
| && i < maxIntDig |
| && !fUseExponentialNotation) { |
| result.append(group); |
| } |
| if (! roundingDigits.empty()) { |
| int32_t pos = roundingDecimalPos - i; |
| if (pos >= 0 && pos < roundingDigits.length()) { |
| result.append((UChar) (roundingDigits.charAt(pos) - kPatternZeroDigit + zero)); |
| continue; |
| } |
| } |
| result.append(i<=getMinimumIntegerDigits() ? zero : digit); |
| } |
| if (getMaximumFractionDigits() > 0 || fDecimalSeparatorAlwaysShown) { |
| result.append(localized ? fSymbols->getDecimalSeparator() : |
| kPatternDecimalSeparator); |
| } |
| int32_t pos = roundingDecimalPos; |
| for (i = 0; i < getMaximumFractionDigits(); ++i) { |
| if (! roundingDigits.empty() && |
| pos < roundingDigits.length()) { |
| result.append(pos < 0 ? zero : |
| (UChar) (roundingDigits.charAt(pos) - kPatternZeroDigit + zero)); |
| ++pos; |
| continue; |
| } |
| result.append(i<getMinimumFractionDigits() ? zero : digit); |
| } |
| if (fUseExponentialNotation) { |
| result.append(localized ? fSymbols->getExponentialSymbol() : |
| kPatternExponent); |
| if (fExponentSignAlwaysShown) { |
| result.append(localized ? fSymbols->getPlusSign() : |
| kPatternPlus); |
| } |
| for (i=0; i<fMinExponentDigits; ++i) { |
| result.append(zero); |
| } |
| } |
| if (! padSpec.empty() && !fUseExponentialNotation) { |
| int32_t add = fFormatWidth - result.length() + sub0Start |
| - ((part == 0) |
| ? fPositivePrefix.length() + fPositiveSuffix.length() |
| : fNegativePrefix.length() + fNegativeSuffix.length()); |
| while (add > 0) { |
| result.insert(sub0Start, digit); |
| --add; |
| if (isGroupingUsed() && fGroupingSize != 0 |
| && ++maxIntDig % fGroupingSize == 0 |
| && add > 1) { |
| result.insert(sub0Start, group); |
| --add; |
| } |
| } |
| } |
| if (fPadPosition == kPadBeforeSuffix && ! padSpec.empty()) { |
| result.append(padSpec); |
| } |
| if (part == 0) { |
| appendAffix(result, fPosSuffixPattern, fPositiveSuffix, localized); |
| if (fPadPosition == kPadAfterSuffix && ! padSpec.empty()) { |
| result.append(padSpec); |
| } |
| bool_t isDefault = FALSE; |
| if ((fNegSuffixPattern == fPosSuffixPattern && // both null |
| fNegativeSuffix == fPositiveSuffix) |
| || (fNegSuffixPattern != 0 && fPosSuffixPattern != 0 && |
| *fNegSuffixPattern == *fPosSuffixPattern)) { |
| if (fNegPrefixPattern != NULL && fPosPrefixPattern != NULL) { |
| int32_t length = fPosPrefixPattern->length(); |
| isDefault = fNegPrefixPattern->length() == (length+2) && |
| (*fNegPrefixPattern)[(UTextOffset)0] == kQuote && |
| (*fNegPrefixPattern)[(UTextOffset)1] == kPatternMinus && |
| fNegPrefixPattern->compare(2, length, *fPosPrefixPattern, 0, length) == 0; |
| } |
| if (!isDefault && |
| fNegPrefixPattern == NULL && fPosPrefixPattern == NULL) { |
| int32_t length = fPositivePrefix.length(); |
| isDefault = fNegativePrefix.length() == (length+1) && |
| fNegativePrefix[(UTextOffset)0] == fSymbols->getMinusSign() && |
| fNegativePrefix.compare(1, length, fPositivePrefix, 0, length) == 0; |
| } |
| } |
| if (isDefault) { |
| break; // Don't output default negative subpattern |
| } else { |
| result.append(localized ? fSymbols->getPatternSeparator() : |
| kPatternSeparator); |
| } |
| } else { |
| appendAffix(result, fNegSuffixPattern, fNegativeSuffix, localized); |
| if (fPadPosition == kPadAfterSuffix && ! padSpec.empty()) { |
| result.append(padSpec); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) |
| { |
| applyPattern(pattern, FALSE, status); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status) |
| { |
| applyPattern(pattern, TRUE, status); |
| } |
| |
| //------------------------------------------------------------------------------ |
| |
| void |
| DecimalFormat::applyPattern(const UnicodeString& pattern, |
| bool_t localized, |
| UErrorCode& status) |
| { |
| if (U_FAILURE(status)) return; |
| // Set the significant pattern symbols |
| UChar zeroDigit = kPatternZeroDigit; |
| UChar groupingSeparator = kPatternGroupingSeparator; |
| UChar decimalSeparator = kPatternDecimalSeparator; |
| UChar percent = kPatternPercent; |
| UChar perMill = kPatternPerMill; |
| UChar digit = kPatternDigit; |
| UChar separator = kPatternSeparator; |
| UChar exponent = kPatternExponent; |
| UChar plus = kPatternPlus; |
| UChar minus = kPatternMinus; |
| UChar padEscape = kPatternPadEscape; |
| // Substitute with the localized symbols if necessary |
| if (localized) { |
| zeroDigit = fSymbols->getZeroDigit(); |
| groupingSeparator = fSymbols->getGroupingSeparator(); |
| decimalSeparator = fSymbols->getDecimalSeparator(); |
| percent = fSymbols->getPercent(); |
| perMill = fSymbols->getPerMill(); |
| digit = fSymbols->getDigit(); |
| separator = fSymbols->getPatternSeparator(); |
| exponent = fSymbols->getExponentialSymbol(); |
| plus = fSymbols->getPlusSign(); |
| minus = fSymbols->getMinusSign(); |
| padEscape = fSymbols->getPadEscape(); |
| } |
| UChar nineDigit = zeroDigit + 9; |
| |
| int32_t pos = 0; |
| // Part 0 is the positive pattern. Part 1, if present, is the negative |
| // pattern. |
| for (int32_t part=0; part<2 && pos<pattern.length(); ++part) { |
| // The subpart ranges from 0 to 4: 0=pattern proper, 1=prefix, |
| // 2=suffix, 3=prefix in quote, 4=suffix in quote. Subpart 0 is |
| // between the prefix and suffix, and consists of pattern |
| // characters. In the prefix and suffix, percent, perMill, and |
| // currency symbols are recognized and translated. |
| int32_t subpart = 1, sub0Start = 0, sub0Limit = 0, sub2Limit = 0; |
| |
| // It's important that we don't change any fields of this object |
| // prematurely. We set the following variables for the multiplier, |
| // grouping, etc., and then only change the actual object fields if |
| // everything parses correctly. This also lets us register |
| // the data from part 0 and ignore the part 1, except for the |
| // prefix and suffix. |
| UnicodeString prefix; |
| UnicodeString suffix; |
| int32_t decimalPos = -1; |
| int32_t multiplier = 1; |
| int32_t digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0; |
| int8_t groupingCount = -1; |
| int32_t padPos = -1; |
| UChar padChar = 0; |
| int32_t roundingPos = -1; |
| DigitList roundingInc; |
| int8_t expDigits = -1; |
| bool_t expSignAlways = FALSE; |
| bool_t isCurrency = FALSE; |
| |
| // The affix is either the prefix or the suffix. |
| UnicodeString* affix = &prefix; |
| |
| int32_t start = pos; |
| bool_t isPartDone = FALSE; |
| |
| for (; !isPartDone && pos < pattern.length(); ++pos) { |
| UChar ch = pattern[(UTextOffset) pos]; |
| switch (subpart) { |
| case 0: // Pattern proper subpart (between prefix & suffix) |
| // Process the digits, decimal, and grouping characters. We |
| // record five pieces of information. We expect the digits |
| // to occur in the pattern ####00.00####, and we record the |
| // number of left digits, zero (central) digits, and right |
| // digits. The position of the last grouping character is |
| // recorded (should be somewhere within the first two blocks |
| // of characters), as is the position of the decimal point, |
| // if any (should be in the zero digits). If there is no |
| // decimal point, then there should be no right digits. |
| if (ch == digit) { |
| if (zeroDigitCount > 0) { |
| ++digitRightCount; |
| } else { |
| ++digitLeftCount; |
| } |
| if (groupingCount >= 0 && decimalPos < 0) { |
| ++groupingCount; |
| } |
| } else if (ch >= zeroDigit && ch <= nineDigit) { |
| if (digitRightCount > 0) { |
| // Unexpected '0' |
| debug("Unexpected '0'") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| ++zeroDigitCount; |
| if (groupingCount >= 0 && decimalPos < 0) { |
| ++groupingCount; |
| } |
| if (ch != zeroDigit && roundingPos < 0) { |
| roundingPos = digitLeftCount + zeroDigitCount; |
| } |
| if (roundingPos >= 0) { |
| roundingInc.append((char)(ch - zeroDigit + '0')); |
| } |
| } else if (ch == groupingSeparator) { |
| if (decimalPos >= 0) { |
| // Grouping separator after decimal |
| debug("Grouping separator after decimal") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| groupingCount = 0; |
| } else if (ch == decimalSeparator) { |
| if (decimalPos >= 0) { |
| // Multiple decimal separators |
| debug("Multiple decimal separators") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| // Intentionally incorporate the digitRightCount, |
| // even though it is illegal for this to be > 0 |
| // at this point. We check pattern syntax below. |
| decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; |
| } else { |
| if (ch == exponent) { |
| if (expDigits >= 0) { |
| // Multiple exponential symbols |
| debug("Multiple exponential symbols") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| if (groupingCount >= 0) { |
| // Grouping separator in exponential pattern |
| debug("Grouping separator in exponential pattern") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| // Check for positive prefix |
| if ((pos+1) < pattern.length() |
| && pattern[(UTextOffset) (pos+1)] == plus) { |
| expSignAlways = TRUE; |
| ++pos; |
| } |
| // Use lookahead to parse out the exponential part of the |
| // pattern, then jump into suffix subpart. |
| expDigits = 0; |
| while (++pos < pattern.length() && |
| pattern[(UTextOffset) pos] == zeroDigit) { |
| ++expDigits; |
| } |
| |
| if ((digitLeftCount + zeroDigitCount) < 1 || |
| expDigits < 1) { |
| // Malformed exponential pattern |
| debug("Malformed exponential pattern") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| } |
| // Transition to suffix subpart |
| subpart = 2; // suffix subpart |
| affix = &suffix; |
| sub0Limit = pos--; |
| continue; |
| } |
| break; |
| case 1: // Prefix subpart |
| case 2: // Suffix subpart |
| // Process the prefix / suffix characters |
| // Process unquoted characters seen in prefix or suffix |
| // subpart. |
| if (ch == digit || |
| ch == groupingSeparator || |
| ch == decimalSeparator || |
| (ch >= zeroDigit && ch <= nineDigit)) { |
| // Any of these characters implicitly begins the |
| // next subpart if we are in the prefix |
| if (subpart == 1) { // prefix subpart |
| subpart = 0; // pattern proper subpart |
| sub0Start = pos--; // Reprocess this character |
| continue; |
| } |
| // Fall through to append(ch) |
| } else if (ch == kCurrencySign) { |
| // Use lookahead to determine if the currency sign is |
| // doubled or not. |
| bool_t doubled = (pos + 1) < pattern.length() && |
| pattern[(UTextOffset) (pos+1)] == kCurrencySign; |
| affix->append(kQuote); // Encode currency |
| if (doubled) { |
| affix->append(kCurrencySign); |
| ++pos; // Skip over the doubled character |
| } |
| isCurrency = TRUE; |
| // Fall through to append(ch) |
| } else if (ch == kQuote) { |
| // A quote outside quotes indicates either the opening |
| // quote or two quotes, which is a quote literal. That is, |
| // we have the first quote in 'do' or o''clock. |
| if ((pos+1) < pattern.length() && |
| pattern[(UTextOffset) (pos+1)] == kQuote) { |
| ++pos; |
| affix->append(kQuote); // Encode quote |
| // Fall through to append(ch) |
| } else { |
| subpart += 2; // open quote |
| continue; |
| } |
| } else if (ch == separator) { |
| // Don't allow separators in the prefix, and don't allow |
| // separators in the second pattern (part == 1). |
| if (subpart == 1 || part == 1) { |
| // Unexpected separator |
| debug("Unexpected separator") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| sub2Limit = pos; |
| isPartDone = TRUE; // Go to next part |
| break; |
| } else if (ch == percent || ch == perMill) { |
| // Next handle characters which are appended directly. |
| if (multiplier != 1) { |
| // Too many percent/perMill characters |
| debug("Too many percent/perMill characters") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| affix->append(kQuote); // Encode percent/perMill |
| if (ch == percent) { |
| multiplier = 100; |
| ch = kPatternPercent; // Use unlocalized pattern char |
| } else { |
| multiplier = 1000; |
| ch = kPatternPerMill; // Use unlocalized pattern char |
| } |
| // Fall through to append(ch) |
| } else if (ch == padEscape) { |
| if (padPos >= 0 || // Multiple pad specifiers |
| (pos+1) == pattern.length()) { // Nothing after padEscape |
| debug("Multiple pad specifiers") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| padPos = pos; |
| padChar = pattern[(UTextOffset) ++pos]; |
| continue; |
| } else if (ch == minus) { |
| affix->append(kQuote); // Encode minus |
| ch = kPatternMinus; |
| // Fall through to append(ch) |
| } else if (ch == plus) { |
| affix->append(kQuote); // Encode plus |
| ch = kPatternPlus; |
| // Fall through to append(ch) |
| } |
| // Unquoted, non-special characters fall through to here, as |
| // well as other code which needs to append something to the |
| // affix. |
| affix->append(ch); |
| break; |
| case 3: // Prefix subpart, in quote |
| case 4: // Suffix subpart, in quote |
| // A quote within quotes indicates either the closing |
| // quote or two quotes, which is a quote literal. That is, |
| // we have the second quote in 'do' or 'don''t'. |
| if (ch == kQuote) { |
| if ((pos+1) < pattern.length() && |
| pattern[(UTextOffset) (pos+1)] == kQuote) { |
| ++pos; |
| affix->append(kQuote); // Encode quote |
| // Fall through to append(ch) |
| } else { |
| subpart -= 2; // close quote |
| continue; |
| } |
| } |
| affix->append(ch); |
| break; |
| } |
| } |
| |
| if (sub0Limit == 0) { |
| sub0Limit = pattern.length(); |
| } |
| |
| if (sub2Limit == 0) { |
| sub2Limit = pattern.length(); |
| } |
| |
| /* Handle patterns with no '0' pattern character. These patterns |
| * are legal, but must be recodified to make sense. "##.###" -> |
| * "#0.###". ".###" -> ".0##". |
| * |
| * We allow patterns of the form "####" to produce a zeroDigitCount |
| * of zero (got that?); although this seems like it might make it |
| * possible for format() to produce empty strings, format() checks |
| * for this condition and outputs a zero digit in this situation. |
| * Having a zeroDigitCount of zero yields a minimum integer digits |
| * of zero, which allows proper round-trip patterns. We don't want |
| * "#" to become "#0" when toPattern() is called (even though that's |
| * what it really is, semantically). |
| */ |
| if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { |
| // Handle "###.###" and "###." and ".###" |
| int n = decimalPos; |
| if (n == 0) ++n; // Handle ".###" |
| digitRightCount = digitLeftCount - n; |
| digitLeftCount = n - 1; |
| zeroDigitCount = 1; |
| } |
| |
| // Do syntax checking on the digits, decimal points, and quotes. |
| if ((decimalPos < 0 && digitRightCount > 0) || |
| (decimalPos >= 0 && |
| (decimalPos < digitLeftCount || |
| decimalPos > (digitLeftCount + zeroDigitCount))) || |
| groupingCount == 0 || |
| subpart > 2) { // subpart > 2 == unmatched quote |
| debug("Syntax error") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| |
| // Make sure pad is at legal position before or after affix. |
| if (padPos >= 0) { |
| if (padPos == start) { |
| padPos = kPadBeforePrefix; |
| } else if (padPos+2 == sub0Start) { |
| padPos = kPadAfterPrefix; |
| } else if (padPos == sub0Limit) { |
| padPos = kPadBeforeSuffix; |
| } else if (padPos+2 == sub2Limit) { |
| padPos = kPadAfterSuffix; |
| } else { |
| // Illegal pad position |
| debug("Illegal pad position") |
| status = U_ILLEGAL_ARGUMENT_ERROR; |
| return; |
| } |
| } |
| |
| if (part == 0) { |
| delete fPosPrefixPattern; |
| delete fPosSuffixPattern; |
| delete fNegPrefixPattern; |
| delete fNegSuffixPattern; |
| fPosPrefixPattern = new UnicodeString(prefix); |
| fPosSuffixPattern = new UnicodeString(suffix); |
| fNegPrefixPattern = 0; |
| fNegSuffixPattern = 0; |
| |
| fUseExponentialNotation = (expDigits >= 0); |
| if (fUseExponentialNotation) { |
| fMinExponentDigits = expDigits; |
| fExponentSignAlwaysShown = expSignAlways; |
| } |
| fIsCurrencyFormat = isCurrency; |
| int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; |
| // The effectiveDecimalPos is the position the decimal is at or |
| // would be at if there is no decimal. Note that if |
| // decimalPos<0, then digitTotalCount == digitLeftCount + |
| // zeroDigitCount. |
| int effectiveDecimalPos = decimalPos >= 0 ? decimalPos : digitTotalCount; |
| setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount); |
| setMaximumIntegerDigits(fUseExponentialNotation |
| ? digitLeftCount + getMinimumIntegerDigits() |
| : kDoubleIntegerDigits); |
| setMaximumFractionDigits(decimalPos >= 0 |
| ? (digitTotalCount - decimalPos) : 0); |
| setMinimumFractionDigits(decimalPos >= 0 |
| ? (digitLeftCount + zeroDigitCount - decimalPos) : 0); |
| setGroupingUsed(groupingCount > 0); |
| fGroupingSize = (groupingCount > 0) ? groupingCount : 0; |
| fMultiplier = multiplier; |
| setDecimalSeparatorAlwaysShown(decimalPos == 0 |
| || decimalPos == digitTotalCount); |
| if (padPos >= 0) { |
| fPadPosition = (EPadPosition) padPos; |
| // To compute the format width, first set up sub0Limit - |
| // sub0Start. Add in prefix/suffix length later. |
| |
| // fFormatWidth = prefix.length() + suffix.length() + |
| // sub0Limit - sub0Start; |
| fFormatWidth = sub0Limit - sub0Start; |
| fPad = padChar; |
| } else { |
| fFormatWidth = 0; |
| } |
| if (roundingPos >= 0) { |
| roundingInc.fDecimalAt = effectiveDecimalPos - roundingPos; |
| if (fRoundingIncrement != NULL) { |
| *fRoundingIncrement = roundingInc; |
| } else { |
| fRoundingIncrement = new DigitList(roundingInc); |
| } |
| fRoundingDouble = fRoundingIncrement->getDouble(); |
| fRoundingMode = kRoundHalfEven; |
| } else { |
| setRoundingIncrement(0.0); |
| } |
| } else { |
| fNegPrefixPattern = new UnicodeString(prefix); |
| fNegSuffixPattern = new UnicodeString(suffix); |
| } |
| } |
| |
| if (pattern.length() == 0) { |
| delete fNegPrefixPattern; |
| delete fNegSuffixPattern; |
| fNegPrefixPattern = NULL; |
| fNegSuffixPattern = NULL; |
| if (fPosPrefixPattern != NULL) { |
| fPosPrefixPattern->remove(); |
| } else { |
| fPosPrefixPattern = new UnicodeString(); |
| } |
| if (fPosSuffixPattern != NULL) { |
| fPosSuffixPattern->remove(); |
| } else { |
| fPosSuffixPattern = new UnicodeString(); |
| } |
| |
| setMinimumIntegerDigits(0); |
| setMaximumIntegerDigits(kDoubleIntegerDigits); |
| setMinimumFractionDigits(0); |
| setMaximumFractionDigits(kDoubleFractionDigits); |
| |
| fUseExponentialNotation = FALSE; |
| fIsCurrencyFormat = FALSE; |
| setGroupingUsed(FALSE); |
| fGroupingSize = 0; |
| fMultiplier = 1; |
| setDecimalSeparatorAlwaysShown(FALSE); |
| fFormatWidth = 0; |
| setRoundingIncrement(0.0); |
| } |
| |
| // If there was no negative pattern, or if the negative pattern is |
| // identical to the positive pattern, then prepend the minus sign to the |
| // positive pattern to form the negative pattern. |
| if (fNegPrefixPattern == NULL || |
| (*fNegPrefixPattern == *fPosPrefixPattern |
| && *fNegSuffixPattern == *fPosSuffixPattern)) { |
| _copy_us_ptr(&fNegSuffixPattern, fPosSuffixPattern); |
| if (fNegPrefixPattern == NULL) { |
| fNegPrefixPattern = new UnicodeString(); |
| } else { |
| fNegPrefixPattern->remove(); |
| } |
| fNegPrefixPattern->append(kQuote).append(kPatternMinus) |
| .append(*fPosPrefixPattern); |
| } |
| #ifdef DEBUG |
| UnicodeString s; |
| s.append("\"").append(pattern).append("\"->"); |
| debugout(s); |
| #endif |
| expandAffixes(); |
| if (fFormatWidth > 0) { |
| // Finish computing format width (see above) |
| fFormatWidth += fPositivePrefix.length() + fPositiveSuffix.length(); |
| } |
| } |
| |
| /** |
| * Sets the maximum number of digits allowed in the integer portion of a |
| * number. This override limits the integer digit count to 309. |
| * @see NumberFormat#setMaximumIntegerDigits |
| */ |
| void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { |
| NumberFormat::setMaximumIntegerDigits(uprv_min(newValue, kDoubleIntegerDigits)); |
| } |
| |
| /** |
| * Sets the minimum number of digits allowed in the integer portion of a |
| * number. This override limits the integer digit count to 309. |
| * @see NumberFormat#setMinimumIntegerDigits |
| */ |
| void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { |
| NumberFormat::setMinimumIntegerDigits(uprv_min(newValue, kDoubleIntegerDigits)); |
| } |
| |
| /** |
| * Sets the maximum number of digits allowed in the fraction portion of a |
| * number. This override limits the fraction digit count to 340. |
| * @see NumberFormat#setMaximumFractionDigits |
| */ |
| void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { |
| NumberFormat::setMaximumFractionDigits(uprv_min(newValue, kDoubleFractionDigits)); |
| } |
| |
| /** |
| * Sets the minimum number of digits allowed in the fraction portion of a |
| * number. This override limits the fraction digit count to 340. |
| * @see NumberFormat#setMinimumFractionDigits |
| */ |
| void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { |
| NumberFormat::setMinimumFractionDigits(uprv_min(newValue, kDoubleFractionDigits)); |
| } |
| |
| //eof |