home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / text / DecimalFormat.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  67.1 KB  |  1,670 lines

  1. /*
  2.  * @(#)DecimalFormat.java    1.36 98/03/18
  3.  *
  4.  * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
  5.  * (C) Copyright IBM Corp. 1996 - All Rights Reserved
  6.  *
  7.  * Portions copyright (c) 1996-1998 Sun Microsystems, Inc. All Rights Reserved.
  8.  *
  9.  *   The original version of this source code and documentation is copyrighted
  10.  * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
  11.  * materials are provided under terms of a License Agreement between Taligent
  12.  * and Sun. This technology is protected by multiple US and International
  13.  * patents. This notice and attribution to Taligent may not be removed.
  14.  *   Taligent is a registered trademark of Taligent, Inc.
  15.  *
  16.  * Permission to use, copy, modify, and distribute this software
  17.  * and its documentation for NON-COMMERCIAL purposes and without
  18.  * fee is hereby granted provided that this copyright notice
  19.  * appears in all copies. Please refer to the file "copyright.html"
  20.  * for further important copyright and licensing information.
  21.  *
  22.  * SUN MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  23.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  24.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  25.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  26.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  27.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  28.  *
  29.  */
  30.  
  31. package java.text;
  32. import java.util.ResourceBundle;
  33. import java.util.Locale;
  34. import java.io.IOException;
  35. import java.io.ObjectInputStream;
  36. import java.util.Hashtable;
  37.  
  38. /**
  39.  * <code>DecimalFormat</code> is a concrete subclass of <code>NumberFormat</code>
  40.  * for formatting decimal numbers. This class allows for a variety
  41.  * of parameters, and localization to Western, Arabic, or Indic numbers.
  42.  *
  43.  * <p>
  44.  * Normally, you get the proper <code>NumberFormat</code> for a specific
  45.  * locale (including the default locale) using one of <code>NumberFormat</code>'s
  46.  * factory methods such as <code>getInstance</code>. You may then modify it
  47.  * from there (after testing to make sure it is a <code>DecimalFormat</code>,
  48.  * of course!)
  49.  *
  50.  * <p>
  51.  * Either the prefixes or the suffixes must be different for
  52.  * the parse to distinguish positive from negative.
  53.  * Parsing will be unreliable if the digits, thousands or decimal separators
  54.  * are the same, or if any of them occur in the prefixes or suffixes.
  55.  *
  56.  * <p>
  57.  * <strong>Special cases:</strong>
  58.  *
  59.  * <p>
  60.  * <code>NaN</code> is formatted as a single character, typically
  61.  * <code>\\uFFFD</code>.
  62.  *
  63.  * <p>
  64.  * +/-Infinity is formatted as a single character, typically <code>\\u221E</code>,
  65.  * plus the positive and negative pre/suffixes.
  66.  *
  67.  * <p><code>Note:</code> this class is designed for common users; for very
  68.  * large or small numbers, use a format that can express exponential values.
  69.  
  70.  * <p><strong>Example:</strong>
  71.  * <blockquote>
  72.  * <pre>
  73.  * // normally we would have a GUI with a menu for this
  74.  * Locale[] locales = NumberFormat.getAvailableLocales();
  75.  *
  76.  * double myNumber = -1234.56;
  77.  * NumberFormat form;
  78.  *
  79.  * // just for fun, we print out a number with the locale number, currency
  80.  * // and percent format for each locale we can.
  81.  * for (int j = 0; j < 3; ++j) {
  82.  *     System.out.println("FORMAT");
  83.  *     for (int i = 0; i < locales.length; ++i) {
  84.  *         if (locales[i].getCountry().length() == 0) {
  85.  *            // skip language-only
  86.  *            continue;
  87.  *         }
  88.  *         System.out.print(locales[i].getDisplayName());
  89.  *         switch (j) {
  90.  *         default:
  91.  *             form = NumberFormat.getInstance(locales[i]); break;
  92.  *         case 1:
  93.  *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
  94.  *         case 0:
  95.  *             form = NumberFormat.getPercentInstance(locales[i]); break;
  96.  *         }
  97.  *         try {
  98.  *             System.out.print(": " + ((DecimalFormat)form).toPattern()
  99.  *                          + " -> " + form.format(myNumber));
  100.  *         } catch (IllegalArgumentException iae) { }
  101.  *         try {
  102.  *             System.out.println(" -> " + form.parse(form.format(myNumber)));
  103.  *         } catch (ParseException pe) { }
  104.  *     }
  105.  * }
  106.  * </pre>
  107.  * </blockquote>
  108.  * <strong>The following shows the structure of the pattern.</strong>
  109.  * <pre>
  110.  * pattern    := subpattern{;subpattern}
  111.  * subpattern := {prefix}integer{.fraction}{suffix}
  112.  *
  113.  * prefix     := '\\u0000'..'\\uFFFD' - specialCharacters
  114.  * suffix     := '\\u0000'..'\\uFFFD' - specialCharacters
  115.  * integer    := '#'* '0'* '0'
  116.  * fraction   := '0'* '#'*
  117.  *
  118.  * Notation:
  119.  *  X*       0 or more instances of X
  120.  *  (X | Y)  either X or Y.
  121.  *  X..Y     any character from X up to Y, inclusive.
  122.  *  S - T    characters in S, except those in T
  123.  * </pre>
  124.  * The first subpattern is for positive numbers. The second (optional)
  125.  * subpattern is for negative numbers. (In both cases, ',' can occur
  126.  * inside the integer portion--it is just too messy to indicate in BNF.)
  127.  *
  128.  * <p>
  129.  * Here are the special characters used in the parts of the
  130.  * subpattern, with notes on their usage.
  131.  * <pre>
  132.  * Symbol Meaning
  133.  * 0      a digit
  134.  * #      a digit, zero shows as absent
  135.  * .      placeholder for decimal separator
  136.  * ,      placeholder for grouping separator.
  137.  * E      separates mantissa and exponent for exponential formats.
  138.  * ;      separates formats.
  139.  * -      default negative prefix.
  140.  * %      multiply by 100 and show as percentage
  141.  * \u2030 multiply by 1000 and show as per mille
  142.  * \u00A4 currency sign; replaced by currency symbol; if
  143.  *        doubled, replaced by international currency symbol.
  144.  *        If present in a pattern, the monetary decimal separator
  145.  *        is used instead of the decimal separator.
  146.  * X      any other characters can be used in the prefix or suffix
  147.  * '      used to quote special characters in a prefix or suffix.
  148.  * </pre>
  149.  * <p><strong>Notes</strong>
  150.  * <p>
  151.  * If there is no explicit negative subpattern, - is prefixed to the
  152.  * positive form. That is, "0.00" alone is equivalent to "0.00;-0.00".
  153.  * <p>
  154.  * The exponent character must be immediately followed by one or more
  155.  * digit characters. Example: "0.###E0". The number of digit characters
  156.  * after the exponent character gives the minimum exponent digit count;
  157.  * there is no maximum. Negative exponents are denoted using the same
  158.  * prefix and/or suffix specified for the number itself. The minimum
  159.  * number of integer digits is achieved by adjusting the exponent. The
  160.  * maximum number of integer digits, if any, specifies the exponent
  161.  * grouping. For example, 12345 is formatted using "##0.###E0" as
  162.  * "12.345E3".
  163.  * <p>
  164.  * Illegal patterns, such as "#.#.#" or mixing '_' and '*' in the
  165.  * same pattern, will cause an <code>IllegalArgumentException</code> to be
  166.  * thrown. From the message of <code>IllegalArgumentException</code>, you can
  167.  * find the place in the string where the error occurred.
  168.  *
  169.  * <p>
  170.  * The grouping separator is commonly used for thousands, but in some
  171.  * countries for ten-thousands. The interval is a constant number of
  172.  * digits between the grouping characters, such as 100,000,000 or 1,0000,0000.
  173.  * If you supply a pattern with multiple grouping characters, the interval
  174.  * between the last one and the end of the integer is the one that is
  175.  * used. So "#,##,###,####" == "######,####" == "##,####,####".
  176.  *
  177.  * <p>
  178.  * When calling DecimalFormat.parse(String, ParsePosition) and parsing
  179.  * fails, a null object will be returned.  The unchanged parse position
  180.  * also reflects that an error has occurred during parsing.  When calling
  181.  * the convenient method DecimalFormat.parse(String) and parsing fails,
  182.  * a ParseException will be thrown.
  183.  * <p>
  184.  *
  185.  * This class only handles localized digits where the 10 digits
  186.  * are contiguous in Unicode, from 0 to 9. Other digits sets
  187.  * (such as superscripts) would need a different subclass.
  188.  *
  189.  * @see          java.text.Format
  190.  * @see          java.text.NumberFormat
  191.  * @see          java.text.ChoiceFormat
  192.  * @version      1.36 03/18/98
  193.  * @author       Mark Davis
  194.  * @author       Alan Liu
  195.  */
  196. /*
  197.  * Requested Features
  198.  * Symbol Meaning
  199.  * $      currency symbol as decimal point
  200.  * à   escapes text
  201.  * \u2030 divide by 1000 and show as per/mil
  202.  */
  203. public class DecimalFormat extends NumberFormat {
  204.  
  205.     /**
  206.      * Create a DecimalFormat using the default pattern and symbols
  207.      * for the default locale. This is a convenient way to obtain a
  208.      * DecimalFormat when internationalization is not the main concern.
  209.      * <p>
  210.      * To obtain standard formats for a given locale, use the factory methods
  211.      * on NumberFormat such as getNumberInstance. These factories will
  212.      * return the most appropriate sub-class of NumberFormat for a given
  213.      * locale.
  214.      * @see java.text.NumberFormat#getInstance
  215.      * @see java.text.NumberFormat#getNumberInstance
  216.      * @see java.text.NumberFormat#getCurrencyInstance
  217.      * @see java.text.NumberFormat#getPercentInstance
  218.      */
  219.     public DecimalFormat() {
  220.     Locale def = Locale.getDefault();
  221.     /* try to get the pattern from the cache */
  222.     String pattern = (String) cachedLocaleData.get(def);
  223.     if (pattern == null) {  /* cache miss */
  224.         // Get the pattern for the default locale.
  225.         ResourceBundle rb = ResourceBundle.getBundle
  226.         ("java.text.resources.LocaleElements", def);
  227.         String[] all = rb.getStringArray("NumberPatterns");
  228.         pattern = all[0];
  229.         /* update cache */
  230.         cachedLocaleData.put(def, pattern);
  231.     }
  232.  
  233.     /* Always applyPattern after the symbols are set */
  234.         this.symbols = new DecimalFormatSymbols( def );
  235.         applyPattern( pattern, false );
  236.     }
  237.  
  238.  
  239.     /**
  240.      * Create a DecimalFormat from the given pattern and the symbols
  241.      * for the default locale. This is a convenient way to obtain a
  242.      * DecimalFormat when internationalization is not the main concern.
  243.      * <p>
  244.      * To obtain standard formats for a given locale, use the factory methods
  245.      * on NumberFormat such as getNumberInstance. These factories will
  246.      * return the most appropriate sub-class of NumberFormat for a given
  247.      * locale.
  248.      * @param pattern A non-localized pattern string.
  249.      * @exception IllegalArgumentException if the given pattern is invalid.
  250.      * @see java.text.NumberFormat#getInstance
  251.      * @see java.text.NumberFormat#getNumberInstance
  252.      * @see java.text.NumberFormat#getCurrencyInstance
  253.      * @see java.text.NumberFormat#getPercentInstance
  254.      */
  255.     public DecimalFormat(String pattern) {
  256.     // Always applyPattern after the symbols are set
  257.         this.symbols = new DecimalFormatSymbols( Locale.getDefault() );
  258.         applyPattern( pattern, false );
  259.     }
  260.  
  261.  
  262.     /**
  263.      * Create a DecimalFormat from the given pattern and symbols.
  264.      * Use this constructor when you need to completely customize the
  265.      * behavior of the format.
  266.      * <p>
  267.      * To obtain standard formats for a given
  268.      * locale, use the factory methods on NumberFormat such as
  269.      * getInstance or getCurrencyInstance. If you need only minor adjustments
  270.      * to a standard format, you can modify the format returned by
  271.      * a NumberFormat factory method.
  272.      * @param pattern a non-localized pattern string
  273.      * @param symbols the set of symbols to be used
  274.      * @exception IllegalArgumentException if the given pattern is invalid
  275.      * @see java.text.NumberFormat#getInstance
  276.      * @see java.text.NumberFormat#getNumberInstance
  277.      * @see java.text.NumberFormat#getCurrencyInstance
  278.      * @see java.text.NumberFormat#getPercentInstance
  279.      * @see java.text.DecimalFormatSymbols
  280.      */
  281.     public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
  282.         // Always applyPattern after the symbols are set
  283.         this.symbols = (DecimalFormatSymbols)symbols.clone();
  284.         applyPattern( pattern, false );
  285.     }
  286.  
  287.  
  288.     // Overrides
  289.     public StringBuffer format(double number, StringBuffer result,
  290.                                FieldPosition fieldPosition)
  291.     {
  292.         fieldPosition.setBeginIndex(0);
  293.         fieldPosition.setEndIndex(0);
  294.  
  295.         if (Double.isNaN(number))
  296.         {
  297.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  298.             fieldPosition.setBeginIndex(result.length());
  299.  
  300.             result.append(symbols.getNaN());
  301.  
  302.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  303.             fieldPosition.setEndIndex(result.length());
  304.  
  305.             return result;
  306.         }
  307.  
  308.         boolean isNegative = (number < 0.0);
  309.         if (isNegative) number = -number;
  310.  
  311.         // Do this BEFORE checking to see if value is infinite!
  312.         if (multiplier != 1) number *= multiplier;
  313.  
  314.         if (Double.isInfinite(number))
  315.         {
  316.             result.append(isNegative ? negativePrefix : positivePrefix);
  317.  
  318.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  319.             fieldPosition.setBeginIndex(result.length());
  320.  
  321.             result.append(symbols.getInfinity());
  322.  
  323.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  324.             fieldPosition.setEndIndex(result.length());
  325.  
  326.             result.append(isNegative ? negativeSuffix : positiveSuffix);
  327.             return result;
  328.         }
  329.  
  330.         // At this point we are guaranteed a nonnegative finite
  331.         // number.
  332.         synchronized(digitList) {
  333.             digitList.set(number, useExponentialNotation ?
  334.                       getMaximumIntegerDigits() + getMaximumFractionDigits() :
  335.                       getMaximumFractionDigits(),
  336.                       !useExponentialNotation);
  337.  
  338.             return subformat(result, fieldPosition, isNegative, false);
  339.         }
  340.     }
  341.  
  342.     public StringBuffer format(long number, StringBuffer result,
  343.                                FieldPosition fieldPosition)
  344.     {
  345.         fieldPosition.setBeginIndex(0);
  346.         fieldPosition.setEndIndex(0);
  347.  
  348.         boolean isNegative = (number < 0);
  349.         if (isNegative) number = -number;
  350.  
  351.         // In general, long values always represent real finite numbers, so
  352.         // we don't have to check for +/- Infinity or NaN.  However, there
  353.         // is one case we have to be careful of:  The multiplier can push
  354.         // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
  355.         // check for this before multiplying, and if it happens we use doubles
  356.         // instead, trading off accuracy for range.
  357.         if (multiplier != 1 && multiplier != 0)
  358.         {
  359.             boolean useDouble = false;
  360.  
  361.             if (number < 0) // This can only happen if number == Long.MIN_VALUE
  362.             {
  363.             long cutoff = Long.MIN_VALUE / multiplier;
  364.             useDouble = (number < cutoff);
  365.             }
  366.             else
  367.             {
  368.             long cutoff = Long.MAX_VALUE / multiplier;
  369.             useDouble = (number > cutoff);
  370.             }
  371.  
  372.             if (useDouble)
  373.             {
  374.             double dnumber = (double)(isNegative ? -number : number);
  375.             return format(dnumber, result, fieldPosition);
  376.             }
  377.         }
  378.  
  379.         number *= multiplier;
  380.         synchronized(digitList) {
  381.             digitList.set(number, useExponentialNotation ?
  382.                       getMaximumIntegerDigits() + getMaximumFractionDigits() : 0);
  383.  
  384.             return subformat(result, fieldPosition, isNegative, true);
  385.         }
  386.     }
  387.  
  388.     /**
  389.      * Complete the formatting of a finite number.  On entry, the digitList must
  390.      * be filled in with the correct digits.
  391.      */
  392.     private StringBuffer subformat(StringBuffer result, FieldPosition fieldPosition,
  393.                    boolean isNegative, boolean isInteger)
  394.     {
  395.         // NOTE: This isn't required anymore because DigitList takes care of this.
  396.         //
  397.         //  // The negative of the exponent represents the number of leading
  398.         //  // zeros between the decimal and the first non-zero digit, for
  399.         //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
  400.         //  // is more than the maximum fraction digits, then we have an underflow
  401.         //  // for the printed representation.  We recognize this here and set
  402.         //  // the DigitList representation to zero in this situation.
  403.         //
  404.         //  if (-digitList.decimalAt >= getMaximumFractionDigits())
  405.         //  {
  406.         //      digitList.count = 0;
  407.         //  }
  408.  
  409.         char zero = symbols.getZeroDigit();
  410.         int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
  411.         char grouping = symbols.getGroupingSeparator();
  412.         char decimal = isCurrencyFormat ?
  413.             symbols.getMonetaryDecimalSeparator() :
  414.             symbols.getDecimalSeparator();
  415.  
  416.         // We only show a negative prefix if we're actually going to display
  417.         // a non-zero value.  If we're going to display a zero value, then
  418.         // we format it using the positive suffix and prefix.
  419.  
  420.         if (digitList.isZero())
  421.         {
  422.             isNegative = false;
  423.             digitList.decimalAt = 0; // Normalize
  424.         }
  425.  
  426.         result.append(isNegative ? negativePrefix : positivePrefix);
  427.  
  428.         if (useExponentialNotation)
  429.         {
  430.             // Record field information for caller.
  431.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  432.             {
  433.                 fieldPosition.setBeginIndex(result.length());
  434.                 fieldPosition.setEndIndex(-1);
  435.             }
  436.             else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  437.             {
  438.                 fieldPosition.setBeginIndex(-1);
  439.             }
  440.  
  441.             // Minimum integer digits are handled in exponential format by
  442.             // adjusting the exponent.  For example, 0.01234 with 3 minimum
  443.             // integer digits is "123.4E-4".
  444.  
  445.             // Maximum integer digits are interpreted as indicating the
  446.             // repeating range.  This is useful for engineering notation, in
  447.             // which the exponent is restricted to a multiple of 3.  For
  448.             // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
  449.             // If maximum integer digits are defined and are larger than
  450.             // minimum integer digits, then minimum integer digits are
  451.             // ignored.
  452.             int exponent = digitList.decimalAt;
  453.             int repeat = getMaximumIntegerDigits();
  454.             if (repeat > 1 &&
  455.             repeat != getMinimumIntegerDigits())
  456.             {
  457.                 // A repeating range is defined; adjust to it as follows.
  458.                 // If repeat == 3, we have 5,4,3=>3; 2,1,0=>0; -1,-2,-3=>-3;
  459.                 // -4,-5-,6=>-6, etc.  Also, the exponent we have here is
  460.                 // off by one from what we expect; that is, it is for the format
  461.                 // 0.MMMMMx10^n.  So we subtract another 1 to get it in range.
  462.                 exponent -= (exponent < 0) ? repeat : 1;
  463.                 exponent = (exponent / repeat) * repeat;
  464.             }
  465.             else
  466.             {
  467.                 // No repeating range is defined; use minimum integer digits.
  468.                 exponent -= getMinimumIntegerDigits();
  469.             }
  470.  
  471.             // We now output a minimum number of digits, and more if there
  472.             // are more digits, up to the maximum number of digits.  We
  473.             // place the decimal point after the "integer" digits, which
  474.             // are the first (decimalAt - exponent) digits.
  475.             int minimumDigits =
  476.             getMinimumIntegerDigits() + getMinimumFractionDigits();
  477.             // The number of integer digits is handled specially if the number
  478.             // is zero, since then there may be no digits.
  479.             int integerDigits = digitList.isZero() ? getMinimumIntegerDigits() :
  480.             digitList.decimalAt - exponent;
  481.             int totalDigits = digitList.count;
  482.             if (minimumDigits > totalDigits) totalDigits = minimumDigits;
  483.  
  484.             for (int i=0; i<totalDigits; ++i)
  485.             {
  486.                 if (i == integerDigits)
  487.                 {
  488.                     // Record field information for caller.
  489.                     if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  490.                     fieldPosition.setEndIndex(result.length());
  491.  
  492.                     result.append(decimal);
  493.  
  494.                     // Record field information for caller.
  495.                     if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  496.                     fieldPosition.setBeginIndex(result.length());
  497.                 }
  498.                 result.append((i < digitList.count) ?
  499.                           (char)(digitList.digits[i] + zeroDelta) :
  500.                           zero);
  501.             }
  502.  
  503.             // Record field information
  504.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  505.             {
  506.                 if (fieldPosition.getEndIndex() < 0)
  507.                     fieldPosition.setEndIndex(result.length());
  508.             }
  509.             else if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  510.             {
  511.                 if (fieldPosition.getBeginIndex() < 0)
  512.                     fieldPosition.setBeginIndex(result.length());
  513.                 fieldPosition.setEndIndex(result.length());
  514.             }
  515.  
  516.             // The exponent is output using the pattern-specified minimum
  517.             // exponent digits.  There is no maximum limit to the exponent
  518.             // digits, since truncating the exponent would result in an
  519.             // unacceptable inaccuracy.
  520.             result.append(symbols.getExponentialSymbol());
  521.  
  522.             // For zero values, we force the exponent to zero.  We
  523.             // must do this here, and not earlier, because the value
  524.             // is used to determine integer digit count above.
  525.             if (digitList.isZero()) exponent = 0;
  526.  
  527.             boolean negativeExponent = exponent < 0;
  528.             if (negativeExponent) exponent = -exponent;
  529.             result.append(negativeExponent ? negativePrefix : positivePrefix);
  530.             digitList.set(exponent);
  531.             for (int i=digitList.decimalAt; i<minExponentDigits; ++i) result.append(zero);
  532.             for (int i=0; i<digitList.decimalAt; ++i)
  533.             {
  534.                 result.append((i < digitList.count) ?
  535.                           (char)(digitList.digits[i] + zeroDelta) : zero);
  536.             }
  537.             result.append(negativeExponent ? negativeSuffix : positiveSuffix);
  538.         }
  539.         else
  540.         {
  541.             // Record field information for caller.
  542.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  543.                 fieldPosition.setBeginIndex(result.length());
  544.  
  545.             // Output the integer portion.  Here 'count' is the total
  546.             // number of integer digits we will display, including both
  547.             // leading zeros required to satisfy getMinimumIntegerDigits,
  548.             // and actual digits present in the number.
  549.             int count = getMinimumIntegerDigits();
  550.             int digitIndex = 0; // Index into digitList.fDigits[]
  551.             if (digitList.decimalAt > 0 && count < digitList.decimalAt)
  552.                 count = digitList.decimalAt;
  553.  
  554.             // Handle the case where getMaximumIntegerDigits() is smaller
  555.             // than the real number of integer digits.  If this is so, we
  556.             // output the least significant max integer digits.  For example,
  557.             // the value 1997 printed with 2 max integer digits is just "97".
  558.  
  559.             if (count > getMaximumIntegerDigits())
  560.             {
  561.                 count = getMaximumIntegerDigits();
  562.                 digitIndex = digitList.decimalAt - count;
  563.             }
  564.  
  565.             int sizeBeforeIntegerPart = result.length();
  566.             for (int i=count-1; i>=0; --i)
  567.             {
  568.                 if (i < digitList.decimalAt && digitIndex < digitList.count)
  569.                 {
  570.                     // Output a real digit
  571.                     result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
  572.                 }
  573.                 else
  574.                 {
  575.                     // Output a leading zero
  576.                     result.append(zero);
  577.                 }
  578.  
  579.                 // Output grouping separator if necessary.  Don't output a
  580.                 // grouping separator if i==0 though; that's at the end of
  581.                 // the integer part.
  582.                 if (isGroupingUsed() && i>0 && (groupingSize != 0) && (i % groupingSize == 0))
  583.                 {
  584.                     result.append(grouping);
  585.                 }
  586.             }
  587.  
  588.             // Record field information for caller.
  589.             if (fieldPosition.getField() == NumberFormat.INTEGER_FIELD)
  590.             fieldPosition.setEndIndex(result.length());
  591.  
  592.             // Determine whether or not there are any printable fractional
  593.             // digits.  If we've used up the digits we know there aren't.
  594.             boolean fractionPresent = (getMinimumFractionDigits() > 0) ||
  595.             (!isInteger && digitIndex < digitList.count);
  596.  
  597.             // If there is no fraction present, and we haven't printed any
  598.             // integer digits, then print a zero.  Otherwise we won't print
  599.             // _any_ digits, and we won't be able to parse this string.
  600.             if (!fractionPresent && result.length() == sizeBeforeIntegerPart)
  601.                 result.append(zero);
  602.  
  603.             // Output the decimal separator if we always do so.
  604.             if (decimalSeparatorAlwaysShown || fractionPresent)
  605.                 result.append(decimal);
  606.  
  607.             // Record field information for caller.
  608.             if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  609.                 fieldPosition.setBeginIndex(result.length());
  610.  
  611.             for (int i=0; i < getMaximumFractionDigits(); ++i)
  612.             {
  613.                 // Here is where we escape from the loop.  We escape if we've output
  614.                 // the maximum fraction digits (specified in the for expression above).
  615.                 // We also stop when we've output the minimum digits and either:
  616.                 // we have an integer, so there is no fractional stuff to display,
  617.                 // or we're out of significant digits.
  618.                 if (i >= getMinimumFractionDigits() &&
  619.                     (isInteger || digitIndex >= digitList.count))
  620.                     break;
  621.  
  622.                 // Output leading fractional zeros.  These are zeros that come after
  623.                 // the decimal but before any significant digits.  These are only
  624.                 // output if abs(number being formatted) < 1.0.
  625.                 if (-1-i > (digitList.decimalAt-1))
  626.                 {
  627.                     result.append(zero);
  628.                     continue;
  629.                 }
  630.  
  631.                 // Output a digit, if we have any precision left, or a
  632.                 // zero if we don't.  We don't want to output noise digits.
  633.                 if (!isInteger && digitIndex < digitList.count)
  634.                 {
  635.                     result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
  636.                 }
  637.                 else
  638.                 {
  639.                     result.append(zero);
  640.                 }
  641.             }
  642.  
  643.             // Record field information for caller.
  644.             if (fieldPosition.getField() == NumberFormat.FRACTION_FIELD)
  645.             fieldPosition.setEndIndex(result.length());
  646.         }
  647.  
  648.         result.append(isNegative ? negativeSuffix : positiveSuffix);
  649.  
  650.         return result;
  651.     }
  652.  
  653.     public Number parse(String text, ParsePosition parsePosition)
  654.     {
  655.         // special case NaN
  656.         if (text.regionMatches(parsePosition.index, symbols.getNaN(),
  657.                    0, symbols.getNaN().length())) {
  658.             parsePosition.index = parsePosition.index + symbols.getNaN().length();
  659.             return new Double(Double.NaN);
  660.         }
  661.  
  662.         boolean[] status = new boolean[STATUS_LENGTH];
  663.  
  664.         if (!subparse(text, parsePosition, digitList, false, status))
  665.             return null;
  666.  
  667.         double  doubleResult = 0.0;
  668.         long    longResult = 0;
  669.         boolean gotDouble = true;
  670.  
  671.         // Finally, have DigitList parse the digits into a value.
  672.         if (status[STATUS_INFINITE])
  673.         {
  674.             doubleResult = Double.POSITIVE_INFINITY;
  675.         }
  676.         else if (digitList.fitsIntoLong(status[STATUS_POSITIVE]))
  677.         {
  678.             gotDouble = false;
  679.             longResult = digitList.getLong();
  680.         }
  681.         else doubleResult = digitList.getDouble();
  682.  
  683.     // return final value
  684.         if (multiplier != 1)
  685.         {
  686.             if (gotDouble)
  687.                 doubleResult /= multiplier;
  688.             else {
  689.                 doubleResult = ((double)longResult) / multiplier;
  690.                 if (doubleResult < 0) doubleResult = -doubleResult;
  691.             }
  692.         }
  693.  
  694.         if (!status[STATUS_POSITIVE])
  695.         {
  696.             doubleResult = -doubleResult;
  697.             longResult = -longResult;
  698.         }
  699.         // At this point, if we divided the result by the multiplier, the result may
  700.         // fit into a long.  We check for this case and return a long if possible.
  701.         // We must do this AFTER applying the negative (if appropriate) in order to
  702.         // handle the case of LONG_MIN; otherwise, if we do this with a positive value
  703.         // -LONG_MIN, the double is > 0, but the long is < 0.  This is a C++-specific
  704.         // situation.
  705.         if (multiplier != 1)
  706.         {
  707.             longResult = (long)doubleResult;
  708.             gotDouble = (doubleResult != (double)longResult);
  709.         }
  710.  
  711.         return gotDouble ? (Number)new Double(doubleResult) : (Number)new Long(longResult);
  712.     }
  713.  
  714.     private static final int STATUS_INFINITE = 0;
  715.     private static final int STATUS_POSITIVE = 1;
  716.     private static final int STATUS_LENGTH   = 2;
  717.  
  718.     /**
  719.      * Parse the given text into a number.  The text is parsed beginning at
  720.      * parsePosition, until an unparseable character is seen.
  721.      * @param text The string to parse.
  722.      * @param parsePosition The position at which to being parsing.  Upon
  723.      * return, the first unparseable character.
  724.      * @param digits The DigitList to set to the parsed value.
  725.      * @param isExponent If true, parse an exponent.  This means no
  726.      * infinite values and integer only.
  727.      * @param status Upon return contains boolean status flags indicating
  728.      * whether the value was infinite and whether it was positive.
  729.      */
  730.     private final boolean subparse(String text, ParsePosition parsePosition,
  731.                    DigitList digits, boolean isExponent,
  732.                    boolean status[])
  733.     {
  734.         int position = parsePosition.index;
  735.         int oldStart = parsePosition.index;
  736.         int backup;
  737.  
  738.         // check for positivePrefix; take longest
  739.         boolean gotPositive = text.regionMatches(position,positivePrefix,0,
  740.                                                  positivePrefix.length());
  741.         boolean gotNegative = text.regionMatches(position,negativePrefix,0,
  742.                                                  negativePrefix.length());
  743.         if (gotPositive && gotNegative) {
  744.             if (positivePrefix.length() > negativePrefix.length())
  745.                 gotNegative = false;
  746.             else if (positivePrefix.length() < negativePrefix.length())
  747.                 gotPositive = false;
  748.         }
  749.         if (gotPositive) {
  750.             position += positivePrefix.length();
  751.         } else if (gotNegative) {
  752.             position += negativePrefix.length();
  753.         } else {
  754.             parsePosition.errorIndex = position;
  755.             return false;
  756.         }
  757.         // process digits or Inf, find decimal position
  758.         status[STATUS_INFINITE] = false;
  759.         if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
  760.                           symbols.getInfinity().length()))
  761.         {
  762.             position += symbols.getInfinity().length();
  763.             status[STATUS_INFINITE] = true;
  764.         } else {
  765.             // We now have a string of digits, possibly with grouping symbols,
  766.             // and decimal points.  We want to process these into a DigitList.
  767.             // We don't want to put a bunch of leading zeros into the DigitList
  768.             // though, so we keep track of the location of the decimal point,
  769.             // put only significant digits into the DigitList, and adjust the
  770.             // exponent as needed.
  771.  
  772.             digits.decimalAt = digits.count = 0;
  773.             char zero = symbols.getZeroDigit();
  774.             char nine = (char)(zero + 9);
  775.             int zeroDelta = '0' - zero;
  776.             char decimal = isCurrencyFormat ?
  777.             symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator();
  778.             char grouping = symbols.getGroupingSeparator();
  779.             char exponentChar = symbols.getExponentialSymbol();
  780.             boolean sawDecimal = false;
  781.             boolean sawExponent = false;
  782.             int exponent = 0; // Set to the exponent value, if any
  783.  
  784.             // We have to track digitCount ourselves, because digits.count will
  785.             // pin when the maximum allowable digits is reached.
  786.             int digitCount = 0;
  787.  
  788.             backup = -1;
  789.             for (; position < text.length(); ++position)
  790.             {
  791.                 char ch = text.charAt(position);
  792.                 if (ch == zero)
  793.                 {
  794.                     // Cancel out backup setting (see grouping handler below)
  795.                     backup = -1; // Do this BEFORE continue statement below!!!
  796.  
  797.                     // Handle leading zeros
  798.                     if (digits.count == 0)
  799.                     {
  800.                         // Ignore leading zeros in integer part of number.
  801.                         if (!sawDecimal) continue;
  802.  
  803.                         // If we have seen the decimal, but no significant digits yet,
  804.                         // then we account for leading zeros by decrementing the
  805.                         // digits.decimalAt into negative values.
  806.                         --digits.decimalAt;
  807.                     }
  808.                     else
  809.                     {
  810.                         ++digitCount;
  811.                         digits.append((char)(ch + zeroDelta));
  812.                     }
  813.                 }
  814.                 else if (ch > zero && ch <= nine)
  815.                 {
  816.                     ++digitCount;
  817.                     digits.append((char)(ch + zeroDelta));
  818.  
  819.                     // Cancel out backup setting (see grouping handler below)
  820.                     backup = -1;
  821.                 }
  822.                 else if (!isExponent && ch == decimal)
  823.                 {
  824.                     // If we're only parsing integers, or if we ALREADY saw the
  825.                     // decimal, then don't parse this one.
  826.                     if (isParseIntegerOnly() || sawDecimal) break;
  827.                     digits.decimalAt = digitCount; // Not digits.count!
  828.                     sawDecimal = true;
  829.                 }
  830.                 else if (!isExponent && ch == grouping && isGroupingUsed())
  831.                 {
  832.                     // Ignore grouping characters, if we are using them, but require
  833.                     // that they be followed by a digit.  Otherwise we backup and
  834.                     // reprocess them.
  835.                     backup = position;
  836.                 }
  837.                 else if (!isExponent && ch == exponentChar && !sawExponent)
  838.                 {
  839.                     // Process the exponent by recursively calling this method.
  840.                     ParsePosition pos = new ParsePosition(position + 1);
  841.                     boolean[] stat = new boolean[STATUS_LENGTH];
  842.                     DigitList exponentDigits = new DigitList();
  843.  
  844.                     if (subparse(text, pos, exponentDigits, true, stat) &&
  845.                     exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE]))
  846.                     {
  847.                     position = pos.index; // Advance past the exponent
  848.                     exponent = (int)exponentDigits.getLong();
  849.                     if (!stat[STATUS_POSITIVE]) exponent = -exponent;
  850.                     sawExponent = true;
  851.                     }
  852.                     break; // Whether we fail or succeed, we exit this loop
  853.                 }
  854.                 else break;
  855.             }
  856.  
  857.             if (backup != -1) position = backup;
  858.  
  859.             // If there was no decimal point we have an integer
  860.             if (!sawDecimal) digits.decimalAt = digitCount; // Not digits.count!
  861.  
  862.             // Adjust for exponent, if any
  863.             digits.decimalAt += exponent;
  864.         }
  865.  
  866.         // check for positiveSuffix
  867.         if (gotPositive)
  868.             gotPositive = text.regionMatches(position,positiveSuffix,0,
  869.                                              positiveSuffix.length());
  870.         if (gotNegative)
  871.             gotNegative = text.regionMatches(position,negativeSuffix,0,
  872.                                              negativeSuffix.length());
  873.  
  874.         // if both match, take longest
  875.         if (gotPositive && gotNegative) {
  876.             if (positiveSuffix.length() > negativeSuffix.length())
  877.                 gotNegative = false;
  878.             else if (positiveSuffix.length() < negativeSuffix.length())
  879.                 gotPositive = false;
  880.         }
  881.  
  882.         // fail if neither or both
  883.         if (gotPositive == gotNegative) {
  884.             parsePosition.errorIndex = position;
  885.             return false;
  886.         }
  887.  
  888.         parsePosition.index = position +
  889.             (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
  890.  
  891.         status[STATUS_POSITIVE] = gotPositive;
  892.         if (parsePosition.index == oldStart)
  893.             parsePosition.errorIndex = position;
  894.  
  895.         return true;
  896.     }
  897.  
  898.     /**
  899.      * Returns the decimal format symbols, which is generally not changed
  900.      * by the programmer or user.
  901.      * @return desired DecimalFormatSymbols
  902.      * @see java.text.DecimalFormatSymbols
  903.      */
  904.     public DecimalFormatSymbols getDecimalFormatSymbols() {
  905.         try {
  906.             // don't allow multiple references
  907.             return (DecimalFormatSymbols) symbols.clone();
  908.         } catch (Exception foo) {
  909.             return null; // should never happen
  910.         }
  911.     }
  912.  
  913.  
  914.     /**
  915.      * Sets the decimal format symbols, which is generally not changed
  916.      * by the programmer or user.
  917.      * @param newSymbols desired DecimalFormatSymbols
  918.      * @see java.text.DecimalFormatSymbols
  919.      */
  920.     public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
  921.         try {
  922.             // don't allow multiple references
  923.             symbols = (DecimalFormatSymbols) newSymbols.clone();
  924.         } catch (Exception foo) {
  925.             // should never happen
  926.         }
  927.     }
  928.  
  929.     /**
  930.      * Get the positive prefix.
  931.      * <P>Examples: +123, $123, sFr123
  932.      */
  933.     public String getPositivePrefix () {
  934.         return positivePrefix;
  935.     }
  936.  
  937.     /**
  938.      * Set the positive prefix.
  939.      * <P>Examples: +123, $123, sFr123
  940.      */
  941.     public void setPositivePrefix (String newValue) {
  942.         positivePrefix = newValue;
  943.     }
  944.  
  945.     /**
  946.      * Get the negative prefix.
  947.      * <P>Examples: -123, ($123) (with negative suffix), sFr-123
  948.      */
  949.     public String getNegativePrefix () {
  950.         return negativePrefix;
  951.     }
  952.  
  953.     /**
  954.      * Set the negative prefix.
  955.      * <P>Examples: -123, ($123) (with negative suffix), sFr-123
  956.      */
  957.     public void setNegativePrefix (String newValue) {
  958.         negativePrefix = newValue;
  959.     }
  960.  
  961.     /**
  962.      * Get the positive suffix.
  963.      * <P>Example: 123%
  964.      */
  965.     public String getPositiveSuffix () {
  966.         return positiveSuffix;
  967.     }
  968.  
  969.     /**
  970.      * Set the positive suffix.
  971.      * <P>Example: 123%
  972.      */
  973.     public void setPositiveSuffix (String newValue) {
  974.         positiveSuffix = newValue;
  975.     }
  976.  
  977.     /**
  978.      * Get the negative suffix.
  979.      * <P>Examples: -123%, ($123) (with positive suffixes)
  980.      */
  981.     public String getNegativeSuffix () {
  982.         return negativeSuffix;
  983.     }
  984.  
  985.     /**
  986.      * Set the positive suffix.
  987.      * <P>Examples: 123%
  988.      */
  989.     public void setNegativeSuffix (String newValue) {
  990.         negativeSuffix = newValue;
  991.     }
  992.  
  993.     /**
  994.      * Get the multiplier for use in percent, permill, etc.
  995.      * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
  996.      * (For Arabic, use arabic percent symbol).
  997.      * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
  998.      * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
  999.      */
  1000.     public int getMultiplier () {
  1001.         return multiplier;
  1002.     }
  1003.  
  1004.     /**
  1005.      * Set the multiplier for use in percent, permill, etc.
  1006.      * For a percentage, set the suffixes to have "%" and the multiplier to be 100.
  1007.      * (For Arabic, use arabic percent symbol).
  1008.      * For a permill, set the suffixes to have "\u2031" and the multiplier to be 1000.
  1009.      * <P>Examples: with 100, 1.23 -> "123", and "123" -> 1.23
  1010.      */
  1011.     public void setMultiplier (int newValue) {
  1012.         multiplier = newValue;
  1013.     }
  1014.  
  1015.     /**
  1016.      * Return the grouping size. Grouping size is the number of digits between
  1017.      * grouping separators in the integer portion of a number.  For example,
  1018.      * in the number "123,456.78", the grouping size is 3.
  1019.      * @see #setGroupingSize
  1020.      * @see java.text.NumberFormat#isGroupingUsed
  1021.      * @see java.text.DecimalFormatSymbols#getGroupingSeparator
  1022.      */
  1023.     public int getGroupingSize () {
  1024.         return groupingSize;
  1025.     }
  1026.  
  1027.     /**
  1028.      * Set the grouping size. Grouping size is the number of digits between
  1029.      * grouping separators in the integer portion of a number.  For example,
  1030.      * in the number "123,456.78", the grouping size is 3.
  1031.      * @see #getGroupingSize
  1032.      * @see java.text.NumberFormat#setGroupingUsed
  1033.      * @see java.text.DecimalFormatSymbols#setGroupingSeparator
  1034.      */
  1035.     public void setGroupingSize (int newValue) {
  1036.         groupingSize = (byte)newValue;
  1037.     }
  1038.  
  1039.     /**
  1040.      * Allows you to get the behavior of the decimal separator with integers.
  1041.      * (The decimal separator will always appear with decimals.)
  1042.      * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
  1043.      */
  1044.     public boolean isDecimalSeparatorAlwaysShown() {
  1045.         return decimalSeparatorAlwaysShown;
  1046.     }
  1047.  
  1048.     /**
  1049.      * Allows you to set the behavior of the decimal separator with integers.
  1050.      * (The decimal separator will always appear with decimals.)
  1051.      * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
  1052.      */
  1053.     public void setDecimalSeparatorAlwaysShown(boolean newValue) {
  1054.         decimalSeparatorAlwaysShown = newValue;
  1055.     }
  1056.  
  1057.     /**
  1058.      * Standard override; no change in semantics.
  1059.      */
  1060.     public Object clone() {
  1061.         try {
  1062.             DecimalFormat other = (DecimalFormat) super.clone();
  1063.             other.symbols = (DecimalFormatSymbols) symbols.clone();
  1064.             return other;
  1065.         } catch (Exception e) {
  1066.             throw new InternalError();
  1067.         }
  1068.     }
  1069.  
  1070.     /**
  1071.      * Overrides equals
  1072.      */
  1073.     public boolean equals(Object obj)
  1074.     {
  1075.         if (obj == null) return false;
  1076.         if (!super.equals(obj)) return false; // super does class check
  1077.         DecimalFormat other = (DecimalFormat) obj;
  1078.         return (positivePrefix.equals(other.positivePrefix)
  1079.             && positiveSuffix.equals(other.positiveSuffix)
  1080.             && negativePrefix.equals(other.negativePrefix)
  1081.             && negativeSuffix.equals(other.negativeSuffix)
  1082.             && multiplier == other.multiplier
  1083.             && groupingSize == other.groupingSize
  1084.             && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
  1085.             && useExponentialNotation == other.useExponentialNotation
  1086.             && (!useExponentialNotation ||
  1087.                 minExponentDigits == other.minExponentDigits)
  1088.             && symbols.equals(other.symbols));
  1089.     }
  1090.  
  1091.     /**
  1092.      * Overrides hashCode
  1093.      */
  1094.     public int hashCode() {
  1095.         return super.hashCode() * 37 + positivePrefix.hashCode();
  1096.         // just enough fields for a reasonable distribution
  1097.     }
  1098.  
  1099.     /**
  1100.      * Synthesizes a pattern string that represents the current state
  1101.      * of this Format object.
  1102.      * @see #applyPattern
  1103.      */
  1104.     public String toPattern() {
  1105.         return toPattern( false );
  1106.     }
  1107.  
  1108.     /**
  1109.      * Synthesizes a localized pattern string that represents the current
  1110.      * state of this Format object.
  1111.      * @see #applyPattern
  1112.      */
  1113.     public String toLocalizedPattern() {
  1114.         return toPattern( true );
  1115.     }
  1116.  
  1117.     /**
  1118.      * Does the real work of generating a pattern.
  1119.      */
  1120.     private String toPattern(boolean localized) {
  1121.         StringBuffer result = new StringBuffer();
  1122.         for (int j = 1; j >= 0; --j) {
  1123.             if (j == 1)
  1124.                 result.append(positivePrefix);
  1125.             else result.append(negativePrefix);
  1126.         int i;
  1127.         if (useExponentialNotation)
  1128.         {
  1129.         for (i = getMaximumIntegerDigits(); i > 0; --i)
  1130.         {
  1131.             if (i == groupingSize)
  1132.             result.append(localized ? symbols.getGroupingSeparator() :
  1133.                       PATTERN_GROUPING_SEPARATOR);
  1134.             if (i <= getMinimumIntegerDigits())
  1135.             result.append(localized ? symbols.getZeroDigit() :
  1136.                       PATTERN_ZERO_DIGIT);
  1137.             else
  1138.             result.append(localized ? symbols.getDigit() :
  1139.                       PATTERN_DIGIT);
  1140.  
  1141.         }
  1142.         }
  1143.         else
  1144.         {
  1145.         int tempMax = Math.max(groupingSize, getMinimumIntegerDigits())+1;
  1146.         for (i = tempMax; i > 0; --i) {
  1147.             if (i == groupingSize)
  1148.             result.append(localized ? symbols.getGroupingSeparator() :
  1149.                       PATTERN_GROUPING_SEPARATOR);
  1150.             if (i <= getMinimumIntegerDigits()) {
  1151.             result.append(localized ? symbols.getZeroDigit() :
  1152.                       PATTERN_ZERO_DIGIT);
  1153.             } else {
  1154.             result.append(localized ? symbols.getDigit() :
  1155.                       PATTERN_DIGIT);
  1156.             }
  1157.         }
  1158.             }
  1159.             if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
  1160.                 result.append(localized ? symbols.getDecimalSeparator() :
  1161.                               PATTERN_DECIMAL_SEPARATOR);
  1162.             for (i = 0; i < getMaximumFractionDigits(); ++i) {
  1163.                 if (i < getMinimumFractionDigits()) {
  1164.                     result.append(localized ? symbols.getZeroDigit() :
  1165.                                   PATTERN_ZERO_DIGIT);
  1166.                 } else {
  1167.                     result.append(localized ? symbols.getDigit() :
  1168.                                   PATTERN_DIGIT);
  1169.                 }
  1170.             }
  1171.         if (useExponentialNotation)
  1172.         {
  1173.         result.append(localized ? symbols.getExponentialSymbol() :
  1174.                   PATTERN_EXPONENT);
  1175.         for (i=0; i<minExponentDigits; ++i)
  1176.                     result.append(localized ? symbols.getZeroDigit() :
  1177.                                   PATTERN_ZERO_DIGIT);
  1178.         }
  1179.             if (j == 1) {
  1180.                 result.append(positiveSuffix);
  1181.                 if (negativeSuffix.equals(positiveSuffix)) {
  1182.                     if (negativePrefix.equals(symbols.getMinusSign() + positivePrefix))
  1183.                         break;
  1184.                 }
  1185.                 result.append(localized ? symbols.getPatternSeparator() :
  1186.                               PATTERN_SEPARATOR);
  1187.             } else result.append(negativeSuffix);
  1188.         }
  1189.         return result.toString();
  1190.     }
  1191.  
  1192.  
  1193.     /**
  1194.      * Apply the given pattern to this Format object.  A pattern is a
  1195.      * short-hand specification for the various formatting properties.
  1196.      * These properties can also be changed individually through the
  1197.      * various setter methods.
  1198.      * <p>
  1199.      * There is no limit to integer digits are set
  1200.      * by this routine, since that is the typical end-user desire;
  1201.      * use setMaximumInteger if you want to set a real value.
  1202.      * For negative numbers, use a second pattern, separated by a semicolon
  1203.      * <P>Example "#,#00.0#" -> 1,234.56
  1204.      * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
  1205.      * a maximum of 2 fraction digits.
  1206.      * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
  1207.      * <p>In negative patterns, the minimum and maximum counts are ignored;
  1208.      * these are presumed to be set in the positive pattern.
  1209.      */
  1210.     public void applyPattern( String pattern ) {
  1211.         applyPattern( pattern, false );
  1212.     }
  1213.  
  1214.     /**
  1215.      * Apply the given pattern to this Format object.  The pattern
  1216.      * is assumed to be in a localized notation. A pattern is a
  1217.      * short-hand specification for the various formatting properties.
  1218.      * These properties can also be changed individually through the
  1219.      * various setter methods.
  1220.      * <p>
  1221.      * There is no limit to integer digits are set
  1222.      * by this routine, since that is the typical end-user desire;
  1223.      * use setMaximumInteger if you want to set a real value.
  1224.      * For negative numbers, use a second pattern, separated by a semicolon
  1225.      * <P>Example "#,#00.0#" -> 1,234.56
  1226.      * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
  1227.      * a maximum of 2 fraction digits.
  1228.      * <p>Example: "#,#00.0#;(#,#00.0#)" for negatives in parantheses.
  1229.      * <p>In negative patterns, the minimum and maximum counts are ignored;
  1230.      * these are presumed to be set in the positive pattern.
  1231.      */
  1232.     public void applyLocalizedPattern( String pattern ) {
  1233.         applyPattern( pattern, true );
  1234.     }
  1235.  
  1236.     /**
  1237.      * Does the real work of applying a pattern.
  1238.      */
  1239.     private void applyPattern(String pattern, boolean localized)
  1240.     {
  1241.         char zeroDigit         = PATTERN_ZERO_DIGIT;
  1242.         char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
  1243.         char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
  1244.         char percent           = PATTERN_PERCENT;
  1245.         char perMill           = PATTERN_PER_MILLE;
  1246.         char digit             = PATTERN_DIGIT;
  1247.         char separator         = PATTERN_SEPARATOR;
  1248.         char exponent          = PATTERN_EXPONENT;
  1249.         if (localized) {
  1250.             zeroDigit         = symbols.getZeroDigit();
  1251.             groupingSeparator = symbols.getGroupingSeparator();
  1252.             decimalSeparator  = symbols.getDecimalSeparator();
  1253.             percent           = symbols.getPercent();
  1254.             perMill           = symbols.getPerMill();
  1255.             digit             = symbols.getDigit();
  1256.             separator         = symbols.getPatternSeparator();
  1257.             exponent          = symbols.getExponentialSymbol();
  1258.         }
  1259.         boolean gotNegative = false;
  1260.  
  1261.         decimalSeparatorAlwaysShown = false;
  1262.         isCurrencyFormat = false;
  1263.         useExponentialNotation = false;
  1264.  
  1265.         // Two variables are used to record the subrange of the pattern
  1266.         // occupied by phase 1.  This is used during the processing of the
  1267.         // second pattern (the one representing negative numbers) to ensure
  1268.         // that no deviation exists in phase 1 between the two patterns.
  1269.         int phaseOneStart = 0;
  1270.         int phaseOneLength = 0;
  1271.         /** Back-out comment : HShih
  1272.          * boolean phaseTwo = false;
  1273.          */
  1274.  
  1275.         int start = 0;
  1276.         for (int j = 1; j >= 0 && start < pattern.length(); --j)
  1277.         {
  1278.             boolean inQuote = false;
  1279.             StringBuffer prefix = new StringBuffer();
  1280.             StringBuffer suffix = new StringBuffer();
  1281.             int decimalPos = -1;
  1282.             int multiplier = 1;
  1283.             int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
  1284.             byte groupingCount = -1;
  1285.  
  1286.             // The phase ranges from 0 to 2.  Phase 0 is the prefix.  Phase 1 is
  1287.             // the section of the pattern with digits, decimal separator,
  1288.             // grouping characters.  Phase 2 is the suffix.  In phases 0 and 2,
  1289.             // percent, permille, and currency symbols are recognized and
  1290.             // translated.  The separation of the characters into phases is
  1291.             // strictly enforced; if phase 1 characters are to appear in the
  1292.             // suffix, for example, they must be quoted.
  1293.             int phase = 0;
  1294.  
  1295.             // The affix is either the prefix or the suffix.
  1296.             StringBuffer affix = prefix;
  1297.  
  1298.             for (int pos = start; pos < pattern.length(); ++pos)
  1299.             {
  1300.                 char ch = pattern.charAt(pos);
  1301.             switch (phase)
  1302.             {
  1303.                 case 0:
  1304.                 case 2:
  1305.                 // Process the prefix / suffix characters
  1306.                 if (inQuote)
  1307.                 {
  1308.                     // A quote within quotes indicates either the closing
  1309.                     // quote or two quotes, which is a quote literal.  That is,
  1310.                     // we have the second quote in 'do' or 'don''t'.
  1311.                     if (ch == QUOTE)
  1312.                     {
  1313.                         if ((pos+1) < pattern.length() &&
  1314.                         pattern.charAt(pos+1) == QUOTE)
  1315.                         {
  1316.                         ++pos;
  1317.                         affix.append(ch); // 'don''t'
  1318.                         }
  1319.                         else
  1320.                         {
  1321.                         inQuote = false; // 'do'
  1322.                         }
  1323.                         continue;
  1324.                     }
  1325.                 }
  1326.                 else
  1327.                 {
  1328.                     // Process unquoted characters seen in prefix or suffix
  1329.                     // phase.
  1330.                     if (ch == digit ||
  1331.                         ch == zeroDigit ||
  1332.                         ch == groupingSeparator ||
  1333.                         ch == decimalSeparator)
  1334.                     {
  1335.                         // Any of these characters implicitly begins the next
  1336.                         // phase.  If we are in phase 2, there is no next phase,
  1337.                         // so these characters are illegal.
  1338.                         /**
  1339.                          * 1.2 Back-out comment : HShih
  1340.                          * Can't throw exception here.
  1341.                          * if (phase == 2)
  1342.                          *    throw new IllegalArgumentException("Unquoted special character '" +
  1343.                          *                   ch + "' in pattern \"" +
  1344.                          *                   pattern + '"');
  1345.                          */
  1346.                         phase = 1;
  1347.                         if (j == 1) phaseOneStart = pos;
  1348.                         --pos; // Reprocess this character
  1349.                         continue;
  1350.                     }
  1351.                     else if (ch == CURRENCY_SIGN)
  1352.                     {
  1353.                         // Use lookahead to determine if the currency sign is
  1354.                         // doubled or not.
  1355.                         boolean doubled = (pos + 1) < pattern.length() &&
  1356.                         pattern.charAt(pos + 1) == CURRENCY_SIGN;
  1357.                         affix.append(doubled ?
  1358.                              symbols.getInternationalCurrencySymbol() :
  1359.                              symbols.getCurrencySymbol());
  1360.                         if (doubled) ++pos; // Skip over the doubled character
  1361.                         isCurrencyFormat = true;
  1362.                         continue;
  1363.                     }
  1364.                     else if (ch == QUOTE)
  1365.                     {
  1366.                         // A quote outside quotes indicates either the opening
  1367.                         // quote or two quotes, which is a quote literal.  That is,
  1368.                         // we have the first quote in 'do' or o''clock.
  1369.                         if (ch == QUOTE)
  1370.                         {
  1371.                         if ((pos+1) < pattern.length() &&
  1372.                             pattern.charAt(pos+1) == QUOTE)
  1373.                         {
  1374.                             ++pos;
  1375.                             affix.append(ch); // o''clock
  1376.                         }
  1377.                         else
  1378.                         {
  1379.                             inQuote = true; // 'do'
  1380.                         }
  1381.                         continue;
  1382.                         }
  1383.                     }
  1384.                     else if (ch == separator)
  1385.                     {
  1386.                         // Don't allow separators before we see digit characters of phase
  1387.                         // 1, and don't allow separators in the second pattern (j == 0).
  1388.                         if (phase == 0 || j == 0)
  1389.                         throw new IllegalArgumentException("Unquoted special character '" +
  1390.                                            ch + "' in pattern \"" +
  1391.                                            pattern + '"');
  1392.                         start = pos + 1;
  1393.                         pos = pattern.length();
  1394.                         continue;
  1395.                     }
  1396.  
  1397.                     // Next handle characters which are appended directly.
  1398.                     else if (ch == percent)
  1399.                     {
  1400.                         if (multiplier != 1)
  1401.                         throw new IllegalArgumentException("Too many percent/permille characters in pattern \"" +
  1402.                                            pattern + '"');
  1403.                         multiplier = 100;
  1404.                         ch = symbols.getPercent();
  1405.                     }
  1406.                     else if (ch == perMill)
  1407.                     {
  1408.                         if (multiplier != 1)
  1409.                         throw new IllegalArgumentException("Too many percent/permille characters in pattern \"" +
  1410.                                            pattern + '"');
  1411.                         multiplier = 1000;
  1412.                         ch = symbols.getPerMill();
  1413.                     }
  1414.                 }
  1415.                 // Note that if we are within quotes, or if this is an unquoted,
  1416.                 // non-special character, then we usually fall through to here.
  1417.                 affix.append(ch);
  1418.                 break;
  1419.             case 1:
  1420.                 // Phase one must be identical in the two sub-patterns.  We
  1421.                 // enforce this by doing a direct comparison.  While
  1422.                 // processing the first sub-pattern, we just record its
  1423.                 // length.  While processing the second, we compare
  1424.                 // characters.
  1425.                 if (j == 1) ++phaseOneLength;
  1426.                 else
  1427.                 {
  1428.                     /**
  1429.                      * 1.2 Back-out comment : HShih
  1430.                      * if (ch != pattern.charAt(phaseOneStart++))
  1431.                      *    throw new IllegalArgumentException("Subpattern mismatch in \"" +
  1432.                      *                       pattern + '"');
  1433.                      * phaseTwo = true;
  1434.                      */
  1435.                     if (--phaseOneLength == 0)
  1436.                     {
  1437.                         phase = 2;
  1438.                         affix = suffix;
  1439.                     }
  1440.                     continue;
  1441.                 }
  1442.  
  1443.                 // Process the digits, decimal, and grouping characters.  We
  1444.                 // record five pieces of information.  We expect the digits
  1445.                 // to occur in the pattern ####0000.####, and we record the
  1446.                 // number of left digits, zero (central) digits, and right
  1447.                 // digits.  The position of the last grouping character is
  1448.                 // recorded (should be somewhere within the first two blocks
  1449.                 // of characters), as is the position of the decimal point,
  1450.                 // if any (should be in the zero digits).  If there is no
  1451.                 // decimal point, then there should be no right digits.
  1452.                 if (ch == digit)
  1453.                 {
  1454.                     if (zeroDigitCount > 0) ++digitRightCount; else ++digitLeftCount;
  1455.                     if (groupingCount >= 0 && decimalPos < 0) ++groupingCount;
  1456.                 }
  1457.                 else if (ch == zeroDigit)
  1458.                 {
  1459.                     if (digitRightCount > 0)
  1460.                        throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
  1461.                                        pattern + '"');
  1462.                     ++zeroDigitCount;
  1463.                     if (groupingCount >= 0 && decimalPos < 0) ++groupingCount;
  1464.                 }
  1465.                 else if (ch == groupingSeparator)
  1466.                 {
  1467.                     groupingCount = 0;
  1468.                 }
  1469.                 else if (ch == decimalSeparator)
  1470.                 {
  1471.                     if (decimalPos >= 0)
  1472.                         throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
  1473.                                        pattern + '"');
  1474.                     decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
  1475.                 }
  1476.                 else if (ch == exponent)
  1477.                 {
  1478.                     if (useExponentialNotation)
  1479.                         throw new IllegalArgumentException("Multiple exponential " +
  1480.                                        "symbols in pattern \"" +
  1481.                                        pattern + '"');
  1482.                     useExponentialNotation = true;
  1483.                     minExponentDigits = 0;
  1484.  
  1485.                     // Use lookahead to parse out the exponential part of the
  1486.                     // pattern, then jump into phase 2.
  1487.                     while (++pos < pattern.length() &&
  1488.                            pattern.charAt(pos) == zeroDigit)
  1489.                     {
  1490.                         ++minExponentDigits;
  1491.                         ++phaseOneLength;
  1492.                     }
  1493.  
  1494.                     if ((digitLeftCount + zeroDigitCount) < 1 ||
  1495.                         minExponentDigits < 1)
  1496.                         throw new IllegalArgumentException("Malformed exponential " +
  1497.                                            "pattern \"" +
  1498.                                            pattern + '"');
  1499.  
  1500.                     // Transition to phase 2
  1501.                     phase = 2;
  1502.                     affix = suffix;
  1503.                     --pos;
  1504.                     continue;
  1505.                 }
  1506.                 else
  1507.                 {
  1508.                     phase = 2;
  1509.                     affix = suffix;
  1510.                     --pos;
  1511.                     --phaseOneLength;
  1512.                     continue;
  1513.                 }
  1514.                 break;
  1515.             }
  1516.         }
  1517.         /**
  1518.          * 1.2 Back-out comment : HShih
  1519.          * if (phaseTwo && phaseOneLength > 0)
  1520.          *      throw new IllegalArgumentException("Subpattern mismatch in \"" +
  1521.          *                                   pattern + '"');
  1522.          */
  1523.         // Handle patterns with no '0' pattern character.  These patterns
  1524.         // are legal, but must be interpreted.  "##.###" -> "#0.###".
  1525.         // ".###" -> ".0##".
  1526.         if (zeroDigitCount == 0 && digitLeftCount > 0)
  1527.         {
  1528.             if (decimalPos >= 0) // Handle "###.###" and "###." and ".###"
  1529.             {
  1530.                 int n = decimalPos;
  1531.                 if (n == 0) ++n; // Handle ".###"
  1532.                 digitRightCount = digitLeftCount - n;
  1533.                 digitLeftCount = n - 1;
  1534.             }
  1535.             else --digitLeftCount; // Handle "###"
  1536.             zeroDigitCount = 1;
  1537.         }
  1538.  
  1539.         // Do syntax checking on the digits.
  1540.         if ((decimalPos < 0 && digitRightCount > 0) ||
  1541.         (decimalPos >= 0 &&
  1542.          (decimalPos < digitLeftCount ||
  1543.           decimalPos > (digitLeftCount + zeroDigitCount))) ||
  1544.         groupingCount == 0 ||
  1545.         inQuote)
  1546.             throw new IllegalArgumentException("Malformed pattern \"" +
  1547.                                pattern + '"');
  1548.  
  1549.             if (j == 1) {
  1550.                 this.positivePrefix = prefix.toString();
  1551.                 this.positiveSuffix = suffix.toString();
  1552.                 this.negativePrefix = positivePrefix;   // assume these for now
  1553.                 this.negativeSuffix = positiveSuffix;
  1554.             int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
  1555.             setMinimumIntegerDigits(decimalPos >= 0 ? (decimalPos - digitLeftCount) : 0);
  1556.             // Handles the "0000" like patterns by recording the correct decimal
  1557.             // position.  HShih
  1558.             if (zeroDigitCount > 1 && digitLeftCount == 0 && digitRightCount == 0)
  1559.                 setMinimumIntegerDigits(zeroDigitCount);
  1560.             // Handles "#,##0" and "#,000" correctly
  1561.             else if (zeroDigitCount > 0 && digitLeftCount > 0 && zeroDigitCount != digitLeftCount && (digitTotalCount == digitLeftCount + zeroDigitCount))
  1562.                 setMinimumIntegerDigits(zeroDigitCount);
  1563.             setMaximumIntegerDigits(useExponentialNotation ?
  1564.                         digitLeftCount + getMinimumIntegerDigits() : 127);
  1565.             setMaximumFractionDigits(decimalPos >= 0 ? (digitTotalCount - decimalPos) : 0);
  1566.             setMinimumFractionDigits(decimalPos >= 0 ?
  1567.                          (digitLeftCount + zeroDigitCount - decimalPos) : 0);
  1568.             setGroupingUsed(groupingCount > 0);
  1569.             this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
  1570.             this.multiplier = multiplier;
  1571.             setDecimalSeparatorAlwaysShown(decimalPos == 0 || decimalPos == digitTotalCount);
  1572.             } else {
  1573.                 this.negativePrefix = prefix.toString();
  1574.                 this.negativeSuffix = suffix.toString();
  1575.                 gotNegative = true;
  1576.             }
  1577.         }
  1578.  
  1579.     // If there was no negative pattern, or if the negative pattern is identical
  1580.     // to the positive pattern, then prepend the minus sign to the positive
  1581.     // pattern to form the negative pattern.
  1582.         if (!gotNegative ||
  1583.             (negativePrefix.equals(positivePrefix)
  1584.              && negativeSuffix.equals(positiveSuffix))) {
  1585.             negativeSuffix = positiveSuffix;
  1586.             negativePrefix = symbols.getMinusSign() + negativePrefix;
  1587.         }
  1588.     }
  1589.  
  1590.     /**
  1591.      * Override readObject.
  1592.      */
  1593.     private void readObject(ObjectInputStream stream)
  1594.          throws IOException, ClassNotFoundException
  1595.     {
  1596.         stream.defaultReadObject();
  1597.         if (serialVersionOnStream < 1) {
  1598.             // Didn't have exponential fields
  1599.             useExponentialNotation = false;
  1600.         }
  1601.         serialVersionOnStream = currentSerialVersion;
  1602.         digitList = new DigitList();
  1603.     }
  1604.  
  1605.     //----------------------------------------------------------------------
  1606.     // INSTANCE VARIABLES
  1607.     //----------------------------------------------------------------------
  1608.  
  1609.     private transient DigitList digitList = new DigitList();
  1610.  
  1611.     // these are often left as localized
  1612.     private String  positivePrefix = "";
  1613.     private String  positiveSuffix = "";
  1614.     private String  negativePrefix = "-";
  1615.     private String  negativeSuffix = "";
  1616.     private int     multiplier = 1;
  1617.     private byte    groupingSize = 3;  // invariant, > 0 if useThousands
  1618.     private boolean decimalSeparatorAlwaysShown = false;
  1619.     private transient boolean isCurrencyFormat = false;
  1620.     private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
  1621.  
  1622.     private boolean useExponentialNotation;  // New to JDK 1.1.5
  1623.     private byte    minExponentDigits;       // New to JDK 1.1.5
  1624.  
  1625.     //----------------------------------------------------------------------
  1626.  
  1627.     // The internal serial version which says which version was written
  1628.     // - 0 (default) for version up to JDK 1.1.4
  1629.     // - 1 for version from JDK 1.1.5, which includes two new fields
  1630.     static final int currentSerialVersion = 1;
  1631.     private int serialVersionOnStream = currentSerialVersion;
  1632.  
  1633.     //----------------------------------------------------------------------
  1634.     // CONSTANTS
  1635.     //----------------------------------------------------------------------
  1636.  
  1637.     // Constants for characters used in programmatic (unlocalized) patterns.
  1638.     private static final char       PATTERN_ZERO_DIGIT         = '0';
  1639.     private static final char       PATTERN_GROUPING_SEPARATOR = ',';
  1640.     private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
  1641.     private static final char       PATTERN_PER_MILLE          = '\u2030';
  1642.     private static final char       PATTERN_PERCENT            = '%';
  1643.     private static final char       PATTERN_DIGIT              = '#';
  1644.     private static final char       PATTERN_SEPARATOR          = ';';
  1645.     private static final char       PATTERN_EXPONENT           = 'E';
  1646.  
  1647.     /**
  1648.      * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
  1649.      * is used in patterns and substitued with either the currency symbol,
  1650.      * or if it is doubled, with the international currency symbol.  If the
  1651.      * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
  1652.      * replaced with the monetary decimal separator.
  1653.      *
  1654.      * The CURRENCY_SIGN is not localized.
  1655.      */
  1656.     private static final char       CURRENCY_SIGN = '\u00A4';
  1657.  
  1658.     private static final char       QUOTE = '\'';
  1659.  
  1660.     // Proclaim JDK 1.1 serial compatibility.
  1661.     static final long serialVersionUID = 864413376551465018L;
  1662.  
  1663.     /**
  1664.      * Cache to hold the NumberPattern of a Locale.
  1665.      */
  1666.     private static Hashtable cachedLocaleData = new Hashtable(3);
  1667. }
  1668.  
  1669. //eof
  1670.