home *** CD-ROM | disk | FTP | other *** search
- /*
- ********************************************************************************
- * *
- * COPYRIGHT: *
- * (C) Copyright Taligent, Inc., 1997 *
- * (C) Copyright International Business Machines Corporation, 1997-1998 *
- * Licensed Material - Program-Property of IBM - All Rights Reserved. *
- * US Government Users Restricted Rights - Use, duplication, or disclosure *
- * restricted by GSA ADP Schedule Contract with IBM Corp. *
- * *
- ********************************************************************************
- *
- * File NUMFMT.CPP
- *
- * Modification History:
- *
- * Date Name Description
- * 02/19/97 aliu Converted from java.
- * 03/18/97 clhuang Implemented with C++ APIs.
- * 04/17/97 aliu Enlarged MAX_INTEGER_DIGITS to fully accomodate the
- * largest double, by default.
- * Changed DigitCount to int per code review.
- * 07/20/98 stephen Changed operator== to check for grouping
- * Changed setMaxIntegerDigits per Java implementation.
- * Changed setMinIntegerDigits per Java implementation.
- * Changed setMinFractionDigits per Java implementation.
- * Changed setMaxFractionDigits per Java implementation.
- ********************************************************************************
- */
-
- #include "numfmt.h"
- #include "locid.h"
- #include "resbund.h"
- #include "dcfmtsym.h"
- #include "decimfmt.h"
- #include <float.h>
-
- // *****************************************************************************
- // class NumberFormat
- // *****************************************************************************
-
- char NumberFormat::fgClassID = 0; // Value is irrelevant
-
- // If the maximum base 10 exponent were 4, then the largest number would
- // be 99,999 which has 5 digits.
- const int32_t NumberFormat::fgMaxIntegerDigits = DBL_MAX_10_EXP + 1; // Should be ~40 ? --srl
- const int32_t NumberFormat::fgMinIntegerDigits = 127;
-
- const int32_t NumberFormat::fgNumberPatternsCount = 3;
-
- // If no number pattern can be located for a locale, this is the last
- // resort.
- const UnicodeString NumberFormat::fgLastResortNumberPatterns[] =
- {
- "#0.###;-#0.###", // decimal pattern
- "$#0.00;($#0.00)", // currency pattern
- "#0%", // percent pattern
- "#E0" // scientific pattern
- };
-
- // -------------------------------------
- // default constructor
-
- NumberFormat::NumberFormat()
- : fGroupingUsed(TRUE),
- fMaxIntegerDigits(fgMaxIntegerDigits),
- fMinIntegerDigits(1),
- fMaxFractionDigits(3), // invariant, >= minFractionDigits
- fMinFractionDigits(0),
- fParseIntegerOnly(FALSE)
- {
- }
-
- // -------------------------------------
-
- NumberFormat::~NumberFormat()
- {
- }
-
- // -------------------------------------
- // copy constructor
-
- NumberFormat::NumberFormat(const NumberFormat &source)
- {
- *this = source;
- }
-
- // -------------------------------------
- // assignment operator
-
- NumberFormat&
- NumberFormat::operator=(const NumberFormat& rhs)
- {
- if (this != &rhs)
- {
- fGroupingUsed = rhs.fGroupingUsed;
- fMaxIntegerDigits = rhs.fMaxIntegerDigits;
- fMinIntegerDigits = rhs.fMinIntegerDigits;
- fMaxFractionDigits = rhs.fMaxFractionDigits;
- fMinFractionDigits = rhs.fMinFractionDigits;
- fParseIntegerOnly = rhs.fParseIntegerOnly;
- }
- return *this;
- }
-
- // -------------------------------------
-
- bool_t
- NumberFormat::operator==(const Format& that) const
- {
- NumberFormat* other = (NumberFormat*)&that;
-
- return ((this == &that) ||
- ((Format::operator==(that) &&
- getDynamicClassID()== that.getDynamicClassID() &&
- fMaxIntegerDigits == other->fMaxIntegerDigits &&
- fMinIntegerDigits == other->fMinIntegerDigits &&
- fMaxFractionDigits == other->fMaxFractionDigits &&
- fMinFractionDigits == other->fMinFractionDigits &&
- fGroupingUsed == other->fGroupingUsed &&
- fParseIntegerOnly == other->fParseIntegerOnly)));
- }
-
- // -------------------------------------
- // Formats the number object and save the format
- // result in the toAppendTo string buffer.
-
- UnicodeString&
- NumberFormat::format(const Formattable& obj,
- UnicodeString& toAppendTo,
- FieldPosition& pos,
- UErrorCode& status) const
- {
- if (U_FAILURE(status)) return toAppendTo;
-
- if (obj.getType() == Formattable::kDouble) {
- return format(obj.getDouble(), toAppendTo, pos);
- }
- else if (obj.getType() == Formattable::kLong) {
- return format(obj.getLong(), toAppendTo, pos);
- }
- // can't try to format a non-numeric object
- else {
- status = U_INVALID_FORMAT_ERROR;
- return toAppendTo;
- }
- }
-
- // -------------------------------------
- // Parses the string and save the result object as well
- // as the final parsed position.
-
- void
- NumberFormat::parseObject(const UnicodeString& source,
- Formattable& result,
- ParsePosition& parse_pos) const
- {
- parse(source, result, parse_pos);
- }
-
- // -------------------------------------
- // Formats a double number and save the result in a string.
-
- UnicodeString&
- NumberFormat::format(double number, UnicodeString& toAppendTo) const
- {
- FieldPosition pos(0);
- UErrorCode status = U_ZERO_ERROR;
- return format(Formattable(number), toAppendTo, pos, status);
- }
-
- // -------------------------------------
- // Formats a long number and save the result in a string.
-
- UnicodeString&
- NumberFormat::format(int32_t number, UnicodeString& toAppendTo) const
- {
- FieldPosition pos(0);
- UErrorCode status = U_ZERO_ERROR;
- return format(Formattable(number), toAppendTo, pos, status);
- }
-
- // -------------------------------------
- // Parses the text and save the result object. If the returned
- // parse position is 0, that means the parsing failed, the status
- // code needs to be set to failure. Ignores the returned parse
- // position, otherwise.
-
- void
- NumberFormat::parse(const UnicodeString& text,
- Formattable& result,
- UErrorCode& status) const
- {
- if (U_FAILURE(status)) return;
-
- ParsePosition parsePosition(0);
- parse(text, result, parsePosition);
- if (parsePosition.getIndex() == 0) {
- status = U_INVALID_FORMAT_ERROR;
- }
- }
-
- // -------------------------------------
- // Sets to only parse integers.
-
- void
- NumberFormat::setParseIntegerOnly(bool_t value)
- {
- fParseIntegerOnly = value;
- }
-
- // -------------------------------------
- // Create a number style NumberFormat instance with the default locale.
-
- NumberFormat*
- NumberFormat::createInstance(UErrorCode& status)
- {
- return createInstance(Locale::getDefault(), kNumberStyle, status);
- }
-
- // -------------------------------------
- // Create a number style NumberFormat instance with the inLocale locale.
-
- NumberFormat*
- NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
- {
- return createInstance(inLocale, kNumberStyle, status);
- }
-
- // -------------------------------------
- // Create a currency style NumberFormat instance with the default locale.
-
- NumberFormat*
- NumberFormat::createCurrencyInstance(UErrorCode& status)
- {
- return createInstance(Locale::getDefault(), kCurrencyStyle, status);
- }
-
- // -------------------------------------
- // Create a currency style NumberFormat instance with the inLocale locale.
-
- NumberFormat*
- NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
- {
- return createInstance(inLocale, kCurrencyStyle, status);
- }
-
- // -------------------------------------
- // Create a percent style NumberFormat instance with the default locale.
-
- NumberFormat*
- NumberFormat::createPercentInstance(UErrorCode& status)
- {
- return createInstance(Locale::getDefault(), kPercentStyle, status);
- }
-
- // -------------------------------------
- // Create a percent style NumberFormat instance with the inLocale locale.
-
- NumberFormat*
- NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
- {
- return createInstance(inLocale, kPercentStyle, status);
- }
-
- // -------------------------------------
- // Create a scientific style NumberFormat instance with the default locale.
-
- NumberFormat*
- NumberFormat::createScientificInstance(UErrorCode& status)
- {
- return createInstance(Locale::getDefault(), kScientificStyle, status);
- }
-
- // -------------------------------------
- // Create a scientific style NumberFormat instance with the inLocale locale.
-
- NumberFormat*
- NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
- {
- return createInstance(inLocale, kScientificStyle, status);
- }
-
- // -------------------------------------
-
- const Locale*
- NumberFormat::getAvailableLocales(int32_t& count)
- {
- return Locale::getAvailableLocales(count);
- }
-
- // -------------------------------------
- // Checks if the thousand/10 thousand grouping is used in the
- // NumberFormat instance.
-
- bool_t
- NumberFormat::isGroupingUsed() const
- {
- return fGroupingUsed;
- }
-
- // -------------------------------------
- // Sets to use the thousand/10 thousand grouping in the
- // NumberFormat instance.
-
- void
- NumberFormat::setGroupingUsed(bool_t newValue)
- {
- fGroupingUsed = newValue;
- }
-
- // -------------------------------------
- // Gets the maximum number of digits for the integral part for
- // this NumberFormat instance.
-
- int32_t NumberFormat::getMaximumIntegerDigits() const
- {
- return fMaxIntegerDigits;
- }
-
- // -------------------------------------
- // Sets the maximum number of digits for the integral part for
- // this NumberFormat instance.
-
- void
- NumberFormat::setMaximumIntegerDigits(int32_t newValue)
- {
- fMaxIntegerDigits = icu_max(0, icu_min(newValue, fgMaxIntegerDigits));
- if(fMinIntegerDigits > fMaxIntegerDigits)
- fMinIntegerDigits = fMaxIntegerDigits;
- }
-
- // -------------------------------------
- // Gets the minimum number of digits for the integral part for
- // this NumberFormat instance.
-
- int32_t
- NumberFormat::getMinimumIntegerDigits() const
- {
- return fMinIntegerDigits;
- }
-
- // -------------------------------------
- // Sets the minimum number of digits for the integral part for
- // this NumberFormat instance.
-
- void
- NumberFormat::setMinimumIntegerDigits(int32_t newValue)
- {
- fMinIntegerDigits = icu_max(0, icu_min(newValue, fgMinIntegerDigits));
- if(fMinIntegerDigits > fMaxIntegerDigits)
- fMaxIntegerDigits = fMinIntegerDigits;
- }
-
- // -------------------------------------
- // Gets the maximum number of digits for the fractional part for
- // this NumberFormat instance.
-
- int32_t
- NumberFormat::getMaximumFractionDigits() const
- {
- return fMaxFractionDigits;
- }
-
- // -------------------------------------
- // Sets the maximum number of digits for the fractional part for
- // this NumberFormat instance.
-
- void
- NumberFormat::setMaximumFractionDigits(int32_t newValue)
- {
- fMaxFractionDigits = icu_max(0, icu_min(newValue, fgMaxIntegerDigits));
- if(fMaxFractionDigits < fMinFractionDigits)
- fMinFractionDigits = fMaxFractionDigits;
- }
-
- // -------------------------------------
- // Gets the minimum number of digits for the fractional part for
- // this NumberFormat instance.
-
- int32_t
- NumberFormat::getMinimumFractionDigits() const
- {
- return fMinFractionDigits;
- }
-
- // -------------------------------------
- // Sets the minimum number of digits for the fractional part for
- // this NumberFormat instance.
-
- void
- NumberFormat::setMinimumFractionDigits(int32_t newValue)
- {
- fMinFractionDigits = icu_max(0, icu_min(newValue, fgMinIntegerDigits));
- if (fMaxFractionDigits < fMinFractionDigits)
- fMaxFractionDigits = fMinFractionDigits;
- }
-
- // -------------------------------------
- // Creates the NumberFormat instance of the specified style (number, currency,
- // or percent) for the desired locale.
-
- NumberFormat*
- NumberFormat::createInstance(const Locale& desiredLocale,
- EStyles style,
- UErrorCode& status)
- {
- if (U_FAILURE(status)) return NULL;
-
- if (style < 0 || style >= kStyleCount) {
- status = U_ILLEGAL_ARGUMENT_ERROR;
- return NULL;
- }
-
- ResourceBundle resource(Locale::getDataDirectory(), desiredLocale, status);
- if (U_FAILURE(status))
- {
- // We don't appear to have resource data available -- use the last-resort data
- status = U_USING_FALLBACK_ERROR;
-
- // Use the DecimalFormatSymbols constructor which uses last-resort data
- DecimalFormatSymbols* symbolsToAdopt = new DecimalFormatSymbols(status);
- if (U_FAILURE(status)) { delete symbolsToAdopt; return NULL; } // This should never happen
-
- // Creates a DecimalFormat instance with the last resort number patterns.
- NumberFormat* f = new DecimalFormat(fgLastResortNumberPatterns[style], symbolsToAdopt, status);
- if (U_FAILURE(status)) { delete f; f = NULL; }
- return f;
- }
-
- int32_t patternCount=0;
- const UnicodeString* numberPatterns = resource.getStringArray(DecimalFormat::fgNumberPatterns,
- patternCount, status);
- // If not all the styled patterns exists for the NumberFormat in this locale,
- // sets the status code to failure and returns nil.
- if (patternCount < fgNumberPatternsCount) status = U_INVALID_FORMAT_ERROR;
- if (U_FAILURE(status)) return NULL;
-
- // If the requested style doesn't exist, use a last-resort style.
- // This is to support scientific styles before we have all the
- // resource data in place.
- const UnicodeString& pattern = style < patternCount ?
- numberPatterns[style] : fgLastResortNumberPatterns[style];
-
- // Loads the decimal symbols of the desired locale.
- DecimalFormatSymbols* symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
- if (U_FAILURE(status)) { delete symbolsToAdopt; return NULL; }
-
- // Creates the specified decimal format style of the desired locale.
- NumberFormat* f = new DecimalFormat(pattern, symbolsToAdopt, status);
- if (U_FAILURE(status)) { delete f; f = NULL; }
- return f;
- }
-
- //eof
-