home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Programming / ICU / src / icu / source / i18n / numfmt.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-19  |  14.2 KB  |  456 lines

  1. /*
  2. ********************************************************************************
  3. *                                                                              *
  4. * COPYRIGHT:                                                                   *
  5. *   (C) Copyright Taligent, Inc.,  1997                                        *
  6. *   (C) Copyright International Business Machines Corporation,  1997-1998      *
  7. *   Licensed Material - Program-Property of IBM - All Rights Reserved.         *
  8. *   US Government Users Restricted Rights - Use, duplication, or disclosure    *
  9. *   restricted by GSA ADP Schedule Contract with IBM Corp.                     *
  10. *                                                                              *
  11. ********************************************************************************
  12. *
  13. * File NUMFMT.CPP
  14. *
  15. * Modification History:
  16. *
  17. *   Date        Name        Description
  18. *   02/19/97    aliu        Converted from java.
  19. *   03/18/97    clhuang     Implemented with C++ APIs.
  20. *   04/17/97    aliu        Enlarged MAX_INTEGER_DIGITS to fully accomodate the
  21. *                           largest double, by default.
  22. *                           Changed DigitCount to int per code review.
  23. *    07/20/98    stephen        Changed operator== to check for grouping
  24. *                            Changed setMaxIntegerDigits per Java implementation.
  25. *                            Changed setMinIntegerDigits per Java implementation.
  26. *                            Changed setMinFractionDigits per Java implementation.
  27. *                            Changed setMaxFractionDigits per Java implementation.
  28. ********************************************************************************
  29. */
  30.  
  31. #include "numfmt.h"
  32. #include "locid.h"
  33. #include "resbund.h"
  34. #include "dcfmtsym.h"
  35. #include "decimfmt.h"
  36. #include <float.h>
  37.  
  38. // *****************************************************************************
  39. // class NumberFormat
  40. // *****************************************************************************
  41.  
  42. char NumberFormat::fgClassID = 0; // Value is irrelevant
  43.  
  44. // If the maximum base 10 exponent were 4, then the largest number would 
  45. // be 99,999 which has 5 digits.
  46. const int32_t NumberFormat::fgMaxIntegerDigits = DBL_MAX_10_EXP + 1; // Should be ~40 ? --srl
  47. const int32_t NumberFormat::fgMinIntegerDigits = 127;
  48.  
  49. const int32_t NumberFormat::fgNumberPatternsCount = 3;
  50.  
  51. // If no number pattern can be located for a locale, this is the last
  52. // resort.
  53. const UnicodeString NumberFormat::fgLastResortNumberPatterns[] =
  54. {
  55.     "#0.###;-#0.###",   // decimal pattern
  56.     "$#0.00;($#0.00)",  // currency pattern
  57.     "#0%",              // percent pattern
  58.     "#E0"               // scientific pattern
  59. };
  60.  
  61. // -------------------------------------
  62. // default constructor
  63.  
  64. NumberFormat::NumberFormat()
  65. :   fGroupingUsed(TRUE),
  66.     fMaxIntegerDigits(fgMaxIntegerDigits),
  67.     fMinIntegerDigits(1),
  68.     fMaxFractionDigits(3), // invariant, >= minFractionDigits
  69.     fMinFractionDigits(0),
  70.     fParseIntegerOnly(FALSE)
  71. {
  72. }
  73.  
  74. // -------------------------------------
  75.  
  76. NumberFormat::~NumberFormat()
  77. {
  78. }
  79.  
  80. // -------------------------------------
  81. // copy constructor
  82.  
  83. NumberFormat::NumberFormat(const NumberFormat &source)
  84. {
  85.     *this = source;
  86. }
  87.  
  88. // -------------------------------------
  89. // assignment operator
  90.  
  91. NumberFormat&
  92. NumberFormat::operator=(const NumberFormat& rhs)
  93. {
  94.     if (this != &rhs)
  95.     {
  96.         fGroupingUsed = rhs.fGroupingUsed;
  97.         fMaxIntegerDigits = rhs.fMaxIntegerDigits;
  98.         fMinIntegerDigits = rhs.fMinIntegerDigits;
  99.         fMaxFractionDigits = rhs.fMaxFractionDigits;
  100.         fMinFractionDigits = rhs.fMinFractionDigits;
  101.         fParseIntegerOnly = rhs.fParseIntegerOnly;
  102.     }
  103.     return *this;
  104. }
  105.  
  106. // -------------------------------------
  107.  
  108. bool_t
  109. NumberFormat::operator==(const Format& that) const
  110. {
  111.     NumberFormat* other = (NumberFormat*)&that;
  112.  
  113.     return ((this == &that) ||
  114.             ((Format::operator==(that) &&
  115.               getDynamicClassID()== that.getDynamicClassID() &&
  116.               fMaxIntegerDigits == other->fMaxIntegerDigits &&
  117.               fMinIntegerDigits == other->fMinIntegerDigits &&
  118.               fMaxFractionDigits == other->fMaxFractionDigits &&
  119.               fMinFractionDigits == other->fMinFractionDigits &&
  120.               fGroupingUsed == other->fGroupingUsed &&
  121.               fParseIntegerOnly == other->fParseIntegerOnly)));
  122. }
  123.  
  124. // -------------------------------------
  125. // Formats the number object and save the format
  126. // result in the toAppendTo string buffer.
  127.  
  128. UnicodeString&
  129. NumberFormat::format(const Formattable& obj,
  130.                         UnicodeString& toAppendTo,
  131.                         FieldPosition& pos,
  132.                         UErrorCode& status) const
  133. {
  134.     if (U_FAILURE(status)) return toAppendTo;
  135.  
  136.     if (obj.getType() == Formattable::kDouble) {
  137.         return format(obj.getDouble(), toAppendTo, pos);
  138.     }
  139.     else if (obj.getType() == Formattable::kLong) {
  140.         return format(obj.getLong(), toAppendTo, pos);
  141.     }
  142.     // can't try to format a non-numeric object
  143.     else {
  144.         status = U_INVALID_FORMAT_ERROR;
  145.         return toAppendTo; 
  146.     }
  147. }
  148.   
  149. // -------------------------------------
  150. // Parses the string and save the result object as well
  151. // as the final parsed position.
  152.  
  153. void
  154. NumberFormat::parseObject(const UnicodeString& source,
  155.                              Formattable& result,
  156.                              ParsePosition& parse_pos) const
  157. {
  158.     parse(source, result, parse_pos);
  159. }
  160.  
  161. // -------------------------------------
  162. // Formats a double number and save the result in a string.
  163.  
  164. UnicodeString&
  165. NumberFormat::format(double number, UnicodeString& toAppendTo) const
  166. {
  167.     FieldPosition pos(0);
  168.     UErrorCode status = U_ZERO_ERROR;
  169.     return format(Formattable(number), toAppendTo, pos, status);
  170. }
  171.  
  172. // -------------------------------------
  173. // Formats a long number and save the result in a string.
  174.  
  175. UnicodeString&
  176. NumberFormat::format(int32_t number, UnicodeString& toAppendTo) const
  177. {
  178.     FieldPosition pos(0);
  179.     UErrorCode status = U_ZERO_ERROR;
  180.     return format(Formattable(number), toAppendTo, pos, status);
  181. }
  182.  
  183. // -------------------------------------
  184. // Parses the text and save the result object.  If the returned
  185. // parse position is 0, that means the parsing failed, the status
  186. // code needs to be set to failure.  Ignores the returned parse 
  187. // position, otherwise.
  188.  
  189. void
  190. NumberFormat::parse(const UnicodeString& text,
  191.                         Formattable& result,
  192.                         UErrorCode& status) const
  193. {
  194.     if (U_FAILURE(status)) return;
  195.  
  196.     ParsePosition parsePosition(0);
  197.     parse(text, result, parsePosition);
  198.     if (parsePosition.getIndex() == 0) {
  199.         status = U_INVALID_FORMAT_ERROR;
  200.     }
  201. }
  202.  
  203. // -------------------------------------
  204. // Sets to only parse integers.
  205.  
  206. void
  207. NumberFormat::setParseIntegerOnly(bool_t value)
  208. {
  209.     fParseIntegerOnly = value;
  210. }
  211.  
  212. // -------------------------------------
  213. // Create a number style NumberFormat instance with the default locale.
  214.  
  215. NumberFormat*
  216. NumberFormat::createInstance(UErrorCode& status)
  217. {
  218.     return createInstance(Locale::getDefault(), kNumberStyle, status);
  219. }
  220.  
  221. // -------------------------------------
  222. // Create a number style NumberFormat instance with the inLocale locale.
  223.  
  224. NumberFormat*
  225. NumberFormat::createInstance(const Locale& inLocale, UErrorCode& status)
  226. {
  227.     return createInstance(inLocale, kNumberStyle, status);
  228. }
  229.  
  230. // -------------------------------------
  231. // Create a currency style NumberFormat instance with the default locale.
  232.  
  233. NumberFormat*
  234. NumberFormat::createCurrencyInstance(UErrorCode& status)
  235. {
  236.     return createInstance(Locale::getDefault(), kCurrencyStyle, status);
  237. }
  238.  
  239. // -------------------------------------
  240. // Create a currency style NumberFormat instance with the inLocale locale.
  241.  
  242. NumberFormat*
  243. NumberFormat::createCurrencyInstance(const Locale& inLocale, UErrorCode& status)
  244. {
  245.     return createInstance(inLocale, kCurrencyStyle, status);
  246. }
  247.  
  248. // -------------------------------------
  249. // Create a percent style NumberFormat instance with the default locale.
  250.  
  251. NumberFormat*
  252. NumberFormat::createPercentInstance(UErrorCode& status)
  253. {
  254.     return createInstance(Locale::getDefault(), kPercentStyle, status);
  255. }
  256.  
  257. // -------------------------------------
  258. // Create a percent style NumberFormat instance with the inLocale locale.
  259.  
  260. NumberFormat*
  261. NumberFormat::createPercentInstance(const Locale& inLocale, UErrorCode& status)
  262. {
  263.     return createInstance(inLocale, kPercentStyle, status);
  264. }
  265.  
  266. // -------------------------------------
  267. // Create a scientific style NumberFormat instance with the default locale.
  268.  
  269. NumberFormat*
  270. NumberFormat::createScientificInstance(UErrorCode& status)
  271. {
  272.     return createInstance(Locale::getDefault(), kScientificStyle, status);
  273. }
  274.  
  275. // -------------------------------------
  276. // Create a scientific style NumberFormat instance with the inLocale locale.
  277.  
  278. NumberFormat*
  279. NumberFormat::createScientificInstance(const Locale& inLocale, UErrorCode& status)
  280. {
  281.     return createInstance(inLocale, kScientificStyle, status);
  282. }
  283.  
  284. // -------------------------------------
  285.  
  286. const Locale*
  287. NumberFormat::getAvailableLocales(int32_t& count)
  288. {
  289.     return Locale::getAvailableLocales(count);
  290. }
  291.  
  292. // -------------------------------------
  293. // Checks if the thousand/10 thousand grouping is used in the 
  294. // NumberFormat instance.
  295.  
  296. bool_t
  297. NumberFormat::isGroupingUsed() const
  298. {
  299.     return fGroupingUsed;
  300. }
  301.  
  302. // -------------------------------------
  303. // Sets to use the thousand/10 thousand grouping in the 
  304. // NumberFormat instance.
  305.  
  306. void
  307. NumberFormat::setGroupingUsed(bool_t newValue)
  308. {
  309.     fGroupingUsed = newValue;
  310. }
  311.  
  312. // -------------------------------------
  313. // Gets the maximum number of digits for the integral part for
  314. // this NumberFormat instance.
  315.  
  316. int32_t NumberFormat::getMaximumIntegerDigits() const
  317. {
  318.     return fMaxIntegerDigits;
  319. }
  320.  
  321. // -------------------------------------
  322. // Sets the maximum number of digits for the integral part for
  323. // this NumberFormat instance.
  324.  
  325. void
  326. NumberFormat::setMaximumIntegerDigits(int32_t newValue)
  327. {
  328.     fMaxIntegerDigits = icu_max(0, icu_min(newValue, fgMaxIntegerDigits));
  329.     if(fMinIntegerDigits > fMaxIntegerDigits)
  330.         fMinIntegerDigits = fMaxIntegerDigits;
  331. }
  332.  
  333. // -------------------------------------
  334. // Gets the minimum number of digits for the integral part for
  335. // this NumberFormat instance.
  336.  
  337. int32_t
  338. NumberFormat::getMinimumIntegerDigits() const
  339. {
  340.     return fMinIntegerDigits;
  341. }
  342.  
  343. // -------------------------------------
  344. // Sets the minimum number of digits for the integral part for
  345. // this NumberFormat instance.
  346.  
  347. void
  348. NumberFormat::setMinimumIntegerDigits(int32_t newValue)
  349. {
  350.     fMinIntegerDigits = icu_max(0, icu_min(newValue, fgMinIntegerDigits));
  351.     if(fMinIntegerDigits > fMaxIntegerDigits)
  352.         fMaxIntegerDigits = fMinIntegerDigits;
  353. }
  354.  
  355. // -------------------------------------
  356. // Gets the maximum number of digits for the fractional part for
  357. // this NumberFormat instance.
  358.  
  359. int32_t
  360. NumberFormat::getMaximumFractionDigits() const
  361. {
  362.     return fMaxFractionDigits;
  363. }
  364.  
  365. // -------------------------------------
  366. // Sets the maximum number of digits for the fractional part for
  367. // this NumberFormat instance.
  368.  
  369. void
  370. NumberFormat::setMaximumFractionDigits(int32_t newValue)
  371. {
  372.     fMaxFractionDigits = icu_max(0, icu_min(newValue, fgMaxIntegerDigits));
  373.     if(fMaxFractionDigits < fMinFractionDigits)
  374.         fMinFractionDigits = fMaxFractionDigits;
  375. }
  376.  
  377. // -------------------------------------
  378. // Gets the minimum number of digits for the fractional part for
  379. // this NumberFormat instance.
  380.  
  381. int32_t
  382. NumberFormat::getMinimumFractionDigits() const
  383. {
  384.     return fMinFractionDigits;
  385. }
  386.  
  387. // -------------------------------------
  388. // Sets the minimum number of digits for the fractional part for
  389. // this NumberFormat instance.
  390.  
  391. void
  392. NumberFormat::setMinimumFractionDigits(int32_t newValue)
  393. {
  394.     fMinFractionDigits = icu_max(0, icu_min(newValue, fgMinIntegerDigits));
  395.     if (fMaxFractionDigits < fMinFractionDigits)
  396.         fMaxFractionDigits = fMinFractionDigits;
  397. }
  398.  
  399. // -------------------------------------
  400. // Creates the NumberFormat instance of the specified style (number, currency,
  401. // or percent) for the desired locale.
  402.  
  403. NumberFormat*
  404. NumberFormat::createInstance(const Locale& desiredLocale, 
  405.                              EStyles style, 
  406.                              UErrorCode& status)
  407. {
  408.     if (U_FAILURE(status)) return NULL;
  409.  
  410.     if (style < 0 || style >= kStyleCount) {
  411.         status = U_ILLEGAL_ARGUMENT_ERROR;
  412.         return NULL;
  413.     }
  414.  
  415.     ResourceBundle resource(Locale::getDataDirectory(), desiredLocale, status);
  416.     if (U_FAILURE(status))
  417.     {
  418.         // We don't appear to have resource data available -- use the last-resort data
  419.         status = U_USING_FALLBACK_ERROR;
  420.         
  421.         // Use the DecimalFormatSymbols constructor which uses last-resort data
  422.         DecimalFormatSymbols* symbolsToAdopt = new DecimalFormatSymbols(status);
  423.         if (U_FAILURE(status)) { delete symbolsToAdopt; return NULL; } // This should never happen
  424.  
  425.         // Creates a DecimalFormat instance with the last resort number patterns.
  426.         NumberFormat* f = new DecimalFormat(fgLastResortNumberPatterns[style], symbolsToAdopt, status);
  427.         if (U_FAILURE(status)) { delete f; f = NULL; }
  428.         return f;
  429.     }
  430.  
  431.     int32_t patternCount=0;
  432.     const UnicodeString* numberPatterns = resource.getStringArray(DecimalFormat::fgNumberPatterns,
  433.                                                                   patternCount, status);
  434.     // If not all the styled patterns exists for the NumberFormat in this locale,
  435.     // sets the status code to failure and returns nil.
  436.     if (patternCount < fgNumberPatternsCount) status = U_INVALID_FORMAT_ERROR;
  437.     if (U_FAILURE(status)) return NULL;
  438.  
  439.     // If the requested style doesn't exist, use a last-resort style.
  440.     // This is to support scientific styles before we have all the
  441.     // resource data in place.
  442.     const UnicodeString& pattern = style < patternCount ?
  443.         numberPatterns[style] : fgLastResortNumberPatterns[style];
  444.  
  445.     // Loads the decimal symbols of the desired locale.
  446.     DecimalFormatSymbols* symbolsToAdopt = new DecimalFormatSymbols(desiredLocale, status);
  447.     if (U_FAILURE(status)) { delete symbolsToAdopt; return NULL; }
  448.  
  449.     // Creates the specified decimal format style of the desired locale.
  450.     NumberFormat* f = new DecimalFormat(pattern, symbolsToAdopt, status);
  451.     if (U_FAILURE(status)) { delete f; f = NULL; }
  452.     return f;
  453. }
  454.  
  455. //eof
  456.