mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1438 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1438 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* DecimalFormat.java -- Formats and parses numbers
 | |
|    Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
|  
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| package java.text;
 | |
| 
 | |
| import gnu.java.text.AttributedFormatBuffer;
 | |
| import gnu.java.text.FormatBuffer;
 | |
| import gnu.java.text.FormatCharacterIterator;
 | |
| import gnu.java.text.StringFormatBuffer;
 | |
| 
 | |
| import java.io.IOException;
 | |
| import java.io.ObjectInputStream;
 | |
| import java.util.Currency;
 | |
| import java.util.HashMap;
 | |
| import java.util.Locale;
 | |
| 
 | |
| /**
 | |
|  * @author Tom Tromey (tromey@cygnus.com)
 | |
|  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 | |
|  * @date March 4, 1999
 | |
|  */
 | |
| /* Written using "Java Class Libraries", 2nd edition, plus online
 | |
|  * API docs for JDK 1.2 from http://www.javasoft.com.
 | |
|  * Status:  Believed complete and correct to 1.2.
 | |
|  * Note however that the docs are very unclear about how format parsing
 | |
|  * should work.  No doubt there are problems here.
 | |
|  */
 | |
| public class DecimalFormat extends NumberFormat
 | |
| {
 | |
|   // This is a helper for applyPatternWithSymbols.  It reads a prefix
 | |
|   // or a suffix.  It can cause some side-effects.
 | |
|   private int scanFix (String pattern, int index, FormatBuffer buf,
 | |
|                        String patChars, DecimalFormatSymbols syms,
 | |
|                        boolean is_suffix)
 | |
|     {
 | |
|     int len = pattern.length();
 | |
|     boolean quoteStarted = false;
 | |
|     buf.clear();
 | |
|     
 | |
|     boolean multiplierSet = false;
 | |
|     while (index < len)
 | |
|       {
 | |
| 	char c = pattern.charAt(index);
 | |
| 
 | |
| 	if (quoteStarted)
 | |
| 	  {
 | |
| 	    if (c == '\'')
 | |
| 	      quoteStarted = false;
 | |
| 	    else
 | |
| 	      buf.append(c);
 | |
| 	    index++;
 | |
| 	    continue;
 | |
| 	  }
 | |
| 
 | |
| 	if (c == '\'' && index + 1 < len
 | |
| 	    && pattern.charAt(index + 1) == '\'')
 | |
| 	  {
 | |
| 	    buf.append(c);
 | |
| 	    index++;
 | |
| 	  }
 | |
| 	else if (c == '\'')
 | |
| 	  {
 | |
| 	    quoteStarted = true;
 | |
| 	  }
 | |
| 	else if (c == '\u00a4')
 | |
| 	  {
 | |
| 			/* Currency interpreted later */
 | |
| 			buf.append(c);
 | |
| 		}
 | |
| 	else if (c == syms.getPercent())
 | |
| 	  {
 | |
| 	    if (multiplierSet)
 | |
| 	      throw new IllegalArgumentException ("multiplier already set " +
 | |
| 						  "- index: " + index);
 | |
| 	    multiplierSet = true;
 | |
| 	    multiplier = 100;
 | |
| 	    buf.append(c, NumberFormat.Field.PERCENT);
 | |
| 	  }
 | |
| 	else if (c == syms.getPerMill())
 | |
| 	  {
 | |
| 	    if (multiplierSet)
 | |
| 	      throw new IllegalArgumentException ("multiplier already set " +
 | |
| 						  "- index: " + index);
 | |
| 	    multiplierSet = true;
 | |
| 	    multiplier = 1000;
 | |
| 	    buf.append(c, NumberFormat.Field.PERMILLE);
 | |
| 	  }
 | |
| 	else if (patChars.indexOf(c) != -1)
 | |
| 	  {
 | |
| 	    // This is a pattern character.
 | |
| 	    break;
 | |
| 	  }
 | |
| 	else
 | |
| 		{
 | |
| 			buf.append(c);
 | |
| 		}
 | |
| 	index++;
 | |
|       }
 | |
| 
 | |
|     if (quoteStarted)
 | |
|       throw new IllegalArgumentException ("pattern is lacking a closing quote");
 | |
| 
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   // A helper which reads a number format.
 | |
|   private int scanFormat (String pattern, int index, String patChars,
 | |
|                           DecimalFormatSymbols syms, boolean is_positive)
 | |
|   {
 | |
|     int max = pattern.length();
 | |
| 
 | |
|     int countSinceGroup = 0;
 | |
|     int zeroCount = 0;
 | |
|     boolean saw_group = false;
 | |
| 
 | |
|     //
 | |
|     // Scan integer part.
 | |
|     //
 | |
|     while (index < max)
 | |
|       {
 | |
| 	char c = pattern.charAt(index);
 | |
| 
 | |
| 	if (c == syms.getDigit())
 | |
| 	  {
 | |
| 	    if (zeroCount > 0)
 | |
| 	      throw new IllegalArgumentException ("digit mark following " +
 | |
| 						  "zero - index: " + index);
 | |
| 	    ++countSinceGroup;
 | |
| 	  }
 | |
| 	else if (c == syms.getZeroDigit())
 | |
| 	  {
 | |
| 	    ++zeroCount;
 | |
| 	    ++countSinceGroup;
 | |
| 	  }
 | |
| 	else if (c == syms.getGroupingSeparator())
 | |
| 	  {
 | |
| 	    countSinceGroup = 0;
 | |
| 	    saw_group = true;
 | |
| 	  }
 | |
| 	else
 | |
| 	  break;
 | |
| 
 | |
| 	++index;
 | |
|       }
 | |
| 
 | |
|     // We can only side-effect when parsing the positive format.
 | |
|     if (is_positive)
 | |
|       {
 | |
| 	groupingUsed = saw_group;
 | |
| 	groupingSize = (byte) countSinceGroup;
 | |
| 	// Checking "zeroCount > 0" avoids 0 being formatted into "" with "#".
 | |
| 	if (zeroCount > 0)
 | |
| 	  minimumIntegerDigits = zeroCount;
 | |
|       }
 | |
| 
 | |
|     // Early termination.
 | |
|     if (index == max || pattern.charAt(index) == syms.getGroupingSeparator())
 | |
|       {
 | |
| 	if (is_positive)
 | |
| 	  decimalSeparatorAlwaysShown = false;
 | |
| 	return index;
 | |
|       }
 | |
| 
 | |
|     if (pattern.charAt(index) == syms.getDecimalSeparator())
 | |
|       {
 | |
| 	++index;
 | |
| 
 | |
| 	//
 | |
| 	// Scan fractional part.
 | |
| 	//
 | |
| 	int hashCount = 0;
 | |
| 	zeroCount = 0;
 | |
| 	while (index < max)
 | |
| 	  {
 | |
| 	    char c = pattern.charAt(index);
 | |
| 	    if (c == syms.getZeroDigit())
 | |
| 	      {
 | |
| 		if (hashCount > 0)
 | |
| 		  throw new IllegalArgumentException ("zero mark " +
 | |
| 						      "following digit - index: " + index);
 | |
| 		++zeroCount;
 | |
| 	      }
 | |
| 	    else if (c == syms.getDigit())
 | |
| 	      {
 | |
| 		++hashCount;
 | |
| 	      }
 | |
| 	    else if (c != syms.getExponential()
 | |
| 		     && c != syms.getPatternSeparator()
 | |
| 		     && c != syms.getPercent()
 | |
| 		     && c != syms.getPerMill()
 | |
| 		     && patChars.indexOf(c) != -1)
 | |
| 	      throw new IllegalArgumentException ("unexpected special " +
 | |
| 						  "character - index: " + index);
 | |
| 	    else
 | |
| 	      break;
 | |
| 
 | |
| 	    ++index;
 | |
| 	  }
 | |
| 
 | |
| 	if (is_positive)
 | |
| 	  {
 | |
| 	    maximumFractionDigits = hashCount + zeroCount;
 | |
| 	    minimumFractionDigits = zeroCount;
 | |
| 	  }
 | |
| 
 | |
| 	if (index == max)
 | |
| 	  return index;
 | |
|       }
 | |
| 
 | |
|     if (pattern.charAt(index) == syms.getExponential())
 | |
|       {
 | |
| 	//
 | |
| 	// Scan exponential format.
 | |
| 	//
 | |
| 	zeroCount = 0;
 | |
| 	++index;
 | |
| 	while (index < max)
 | |
| 	  {
 | |
| 	    char c = pattern.charAt(index);
 | |
| 	    if (c == syms.getZeroDigit())
 | |
| 	      ++zeroCount;
 | |
| 	    else if (c == syms.getDigit())
 | |
| 	      {
 | |
| 		if (zeroCount > 0)
 | |
| 		  throw new
 | |
| 		    IllegalArgumentException ("digit mark following zero " +
 | |
| 					      "in exponent - index: " +
 | |
| 					      index);
 | |
| 	      }
 | |
| 	    else if (patChars.indexOf(c) != -1)
 | |
| 	      throw new IllegalArgumentException ("unexpected special " +
 | |
| 						  "character - index: " +
 | |
| 						  index);
 | |
| 	    else
 | |
| 	      break;
 | |
| 
 | |
| 	    ++index;
 | |
| 	  }
 | |
| 
 | |
| 	if (is_positive)
 | |
| 	  {
 | |
| 	    useExponentialNotation = true;
 | |
| 	    minExponentDigits = (byte) zeroCount;
 | |
| 	  }
 | |
| 
 | |
| 	maximumIntegerDigits = groupingSize;
 | |
| 	groupingSize = 0;
 | |
| 	if (maximumIntegerDigits > minimumIntegerDigits && maximumIntegerDigits > 0)
 | |
| 	  {
 | |
| 	    minimumIntegerDigits = 1;
 | |
| 	    exponentRound = maximumIntegerDigits;
 | |
| 	  }
 | |
| 	else
 | |
| 	  exponentRound = 1;
 | |
|       }
 | |
| 
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   // This helper function creates a string consisting of all the
 | |
|   // characters which can appear in a pattern and must be quoted.
 | |
|   private String patternChars (DecimalFormatSymbols syms)
 | |
|   {
 | |
|     StringBuffer buf = new StringBuffer ();
 | |
|     buf.append(syms.getDecimalSeparator());
 | |
|     buf.append(syms.getDigit());
 | |
|     buf.append(syms.getExponential());
 | |
|     buf.append(syms.getGroupingSeparator());
 | |
|     // Adding this one causes pattern application to fail.
 | |
|     // Of course, omitting is causes toPattern to fail.
 | |
|     // ... but we already have bugs there.  FIXME.
 | |
|     // buf.append(syms.getMinusSign());
 | |
|     buf.append(syms.getPatternSeparator());
 | |
|     buf.append(syms.getPercent());
 | |
|     buf.append(syms.getPerMill());
 | |
|     buf.append(syms.getZeroDigit());
 | |
|     buf.append('\u00a4');
 | |
|     return buf.toString();
 | |
|   }
 | |
| 
 | |
|   private void applyPatternWithSymbols(String pattern, DecimalFormatSymbols syms)
 | |
|   {
 | |
|     // Initialize to the state the parser expects.
 | |
|     negativePrefix = "";
 | |
|     negativeSuffix = "";
 | |
|     positivePrefix = "";
 | |
|     positiveSuffix = "";
 | |
|     decimalSeparatorAlwaysShown = false;
 | |
|     groupingSize = 0;
 | |
|     minExponentDigits = 0;
 | |
|     multiplier = 1;
 | |
|     useExponentialNotation = false;
 | |
|     groupingUsed = false;
 | |
|     maximumFractionDigits = 0;
 | |
|     maximumIntegerDigits = MAXIMUM_INTEGER_DIGITS;
 | |
|     minimumFractionDigits = 0;
 | |
|     minimumIntegerDigits = 1;
 | |
| 
 | |
|     AttributedFormatBuffer buf = new AttributedFormatBuffer ();
 | |
|     String patChars = patternChars (syms);
 | |
| 
 | |
|     int max = pattern.length();
 | |
|     int index = scanFix (pattern, 0, buf, patChars, syms, false);
 | |
|     buf.sync();
 | |
|     positivePrefix = buf.getBuffer().toString();
 | |
|     positivePrefixRanges = buf.getRanges();
 | |
|     positivePrefixAttrs = buf.getAttributes();
 | |
| 
 | |
|     index = scanFormat (pattern, index, patChars, syms, true);
 | |
| 
 | |
|     index = scanFix (pattern, index, buf, patChars, syms, true);
 | |
|     buf.sync();
 | |
|     positiveSuffix = buf.getBuffer().toString();
 | |
|     positiveSuffixRanges = buf.getRanges();
 | |
|     positiveSuffixAttrs = buf.getAttributes();
 | |
| 
 | |
|     if (index == pattern.length())
 | |
|       {
 | |
| 	// No negative info.
 | |
| 	negativePrefix = null;
 | |
| 	negativeSuffix = null;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	if (pattern.charAt(index) != syms.getPatternSeparator())
 | |
| 	  throw new IllegalArgumentException ("separator character " +
 | |
| 					      "expected - index: " + index);
 | |
| 
 | |
| 	index = scanFix (pattern, index + 1, buf, patChars, syms, false);
 | |
| 	buf.sync();
 | |
| 	negativePrefix = buf.getBuffer().toString();
 | |
| 	negativePrefixRanges = buf.getRanges();
 | |
| 	negativePrefixAttrs = buf.getAttributes();
 | |
| 
 | |
| 	// We parse the negative format for errors but we don't let
 | |
| 	// it side-effect this object.
 | |
| 	index = scanFormat (pattern, index, patChars, syms, false);
 | |
| 
 | |
| 	index = scanFix (pattern, index, buf, patChars, syms, true);
 | |
| 	buf.sync();
 | |
| 	negativeSuffix = buf.getBuffer().toString();
 | |
| 	negativeSuffixRanges = buf.getRanges();
 | |
| 	negativeSuffixAttrs = buf.getAttributes();
 | |
| 
 | |
| 	if (index != pattern.length())
 | |
| 	  throw new IllegalArgumentException ("end of pattern expected " +
 | |
| 					      "- index: " + index);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public void applyLocalizedPattern (String pattern)
 | |
|   {
 | |
|     // JCL p. 638 claims this throws a ParseException but p. 629
 | |
|     // contradicts this.  Empirical tests with patterns of "0,###.0"
 | |
|     // and "#.#.#" corroborate the p. 629 statement that an
 | |
|     // IllegalArgumentException is thrown.
 | |
|     applyPatternWithSymbols (pattern, symbols);
 | |
|   }
 | |
| 
 | |
|   public void applyPattern (String pattern)
 | |
|   {
 | |
|     // JCL p. 638 claims this throws a ParseException but p. 629
 | |
|     // contradicts this.  Empirical tests with patterns of "0,###.0"
 | |
|     // and "#.#.#" corroborate the p. 629 statement that an
 | |
|     // IllegalArgumentException is thrown.
 | |
|     applyPatternWithSymbols (pattern, nonLocalizedSymbols);
 | |
|   }
 | |
| 
 | |
|   public Object clone ()
 | |
|   {
 | |
|     DecimalFormat c = (DecimalFormat) super.clone ();
 | |
|     c.symbols = (DecimalFormatSymbols) symbols.clone ();
 | |
|     return c;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Constructs a <code>DecimalFormat</code> which uses the default
 | |
|    * pattern and symbols.
 | |
|    */
 | |
|   public DecimalFormat ()
 | |
|   {
 | |
|     this ("#,##0.###");
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Constructs a <code>DecimalFormat</code> which uses the given
 | |
|    * pattern and the default symbols for formatting and parsing.
 | |
|    *
 | |
|    * @param pattern the non-localized pattern to use.
 | |
|    * @throws NullPointerException if any argument is null.
 | |
|    * @throws IllegalArgumentException if the pattern is invalid.
 | |
|    */
 | |
|   public DecimalFormat (String pattern)
 | |
|   {
 | |
|     this (pattern, new DecimalFormatSymbols ());
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Constructs a <code>DecimalFormat</code> using the given pattern
 | |
|    * and formatting symbols.  This construction method is used to give
 | |
|    * complete control over the formatting process.  
 | |
|    *
 | |
|    * @param pattern the non-localized pattern to use.
 | |
|    * @param symbols the set of symbols used for parsing and formatting.
 | |
|    * @throws NullPointerException if any argument is null.
 | |
|    * @throws IllegalArgumentException if the pattern is invalid.
 | |
|    */
 | |
|   public DecimalFormat(String pattern, DecimalFormatSymbols symbols)
 | |
|   {
 | |
|     this.symbols = (DecimalFormatSymbols) symbols.clone();
 | |
|     applyPattern(pattern);
 | |
|   }
 | |
| 
 | |
|   private boolean equals(String s1, String s2)
 | |
|   {
 | |
|     if (s1 == null || s2 == null)
 | |
|       return s1 == s2;
 | |
|     return s1.equals(s2);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Tests this instance for equality with an arbitrary object.  This method
 | |
|    * returns <code>true</code> if:
 | |
|    * <ul>
 | |
|    * <li><code>obj</code> is not <code>null</code>;</li>
 | |
|    * <li><code>obj</code> is an instance of <code>DecimalFormat</code>;</li>
 | |
|    * <li>this instance and <code>obj</code> have the same attributes;</li>
 | |
|    * </ul>
 | |
|    * 
 | |
|    * @param obj  the object (<code>null</code> permitted).
 | |
|    * 
 | |
|    * @return A boolean.
 | |
|    */
 | |
|   public boolean equals(Object obj)
 | |
|   {
 | |
|     if (! (obj instanceof DecimalFormat))
 | |
|       return false;
 | |
|     DecimalFormat dup = (DecimalFormat) obj;
 | |
|     return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown 
 | |
|            && groupingUsed == dup.groupingUsed 
 | |
|            && groupingSize == dup.groupingSize 
 | |
|            && multiplier == dup.multiplier
 | |
|            && useExponentialNotation == dup.useExponentialNotation
 | |
|            && minExponentDigits == dup.minExponentDigits
 | |
|            && minimumIntegerDigits == dup.minimumIntegerDigits
 | |
|            && maximumIntegerDigits == dup.maximumIntegerDigits
 | |
|            && minimumFractionDigits == dup.minimumFractionDigits
 | |
|            && maximumFractionDigits == dup.maximumFractionDigits
 | |
|            && equals(negativePrefix, dup.negativePrefix)
 | |
|            && equals(negativeSuffix, dup.negativeSuffix)
 | |
|            && equals(positivePrefix, dup.positivePrefix)
 | |
|            && equals(positiveSuffix, dup.positiveSuffix)
 | |
|            && symbols.equals(dup.symbols));
 | |
|   }
 | |
| 
 | |
|   private void formatInternal (double number, FormatBuffer dest,
 | |
| 			       FieldPosition fieldPos)
 | |
|   {
 | |
|     // A very special case.
 | |
|     if (Double.isNaN(number))
 | |
|       {
 | |
| 	dest.append(symbols.getNaN());
 | |
| 	if (fieldPos != null && 
 | |
| 	    (fieldPos.getField() == INTEGER_FIELD ||
 | |
| 	     fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
 | |
| 	  {
 | |
| 	    int index = dest.length();
 | |
| 	    fieldPos.setBeginIndex(index - symbols.getNaN().length());
 | |
| 	    fieldPos.setEndIndex(index);
 | |
| 	  }
 | |
| 	return;
 | |
|       }
 | |
| 		
 | |
|     boolean is_neg = number < 0;
 | |
|     if (is_neg)
 | |
|       {
 | |
| 	if (negativePrefix != null)
 | |
| 	  {
 | |
| 	    dest.append(substituteCurrency(negativePrefix, number),
 | |
| 			negativePrefixRanges, negativePrefixAttrs);
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    dest.append(symbols.getMinusSign(), NumberFormat.Field.SIGN);
 | |
| 	    dest.append(substituteCurrency(positivePrefix, number),
 | |
| 			positivePrefixRanges, positivePrefixAttrs);
 | |
| 	  }
 | |
| 	number = - number;
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	dest.append(substituteCurrency(positivePrefix, number),
 | |
| 		    positivePrefixRanges, positivePrefixAttrs);
 | |
|       }
 | |
|     int integerBeginIndex = dest.length();
 | |
|     int integerEndIndex = 0;
 | |
|     int zeroStart = symbols.getZeroDigit() - '0';
 | |
| 		
 | |
|     if (Double.isInfinite (number))
 | |
|       {
 | |
| 	dest.append(symbols.getInfinity());
 | |
| 	integerEndIndex = dest.length();
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	number *= multiplier;
 | |
| 	
 | |
| 	// Compute exponent.
 | |
| 	long exponent = 0;
 | |
| 	double baseNumber;
 | |
| 	if (useExponentialNotation && number > 0)
 | |
| 	  {
 | |
| 	    exponent = (long) Math.floor (Math.log10(number));
 | |
| 	    exponent = exponent - (exponent % exponentRound);
 | |
| 	    if (minimumIntegerDigits > 0)
 | |
| 	      exponent -= minimumIntegerDigits - 1;
 | |
| 	    baseNumber = (number / Math.pow(10.0, exponent));
 | |
| 	  }
 | |
| 	else
 | |
| 	  baseNumber = number;
 | |
| 
 | |
| 	// Round to the correct number of digits.
 | |
| 	baseNumber += 5 * Math.pow(10.0, - maximumFractionDigits - 1);
 | |
| 
 | |
| 	int index = dest.length();
 | |
| 	//double intPart = Math.floor(baseNumber);
 | |
| 	String intPart = Long.toString((long)Math.floor(baseNumber));
 | |
| 	int count, groupPosition = intPart.length();
 | |
| 
 | |
| 	dest.setDefaultAttribute(NumberFormat.Field.INTEGER);
 | |
| 
 | |
| 	for (count = 0; count < minimumIntegerDigits-intPart.length(); count++)
 | |
| 	  dest.append(symbols.getZeroDigit());
 | |
| 
 | |
| 	for (count = 0;
 | |
| 	     count < maximumIntegerDigits && count < intPart.length();
 | |
| 	     count++)
 | |
| 	  {
 | |
| 	    int dig = intPart.charAt(count);
 | |
| 
 | |
| 	    // Append group separator if required.
 | |
| 	    if (groupingUsed && count > 0 && groupingSize != 0 && groupPosition % groupingSize == 0)
 | |
| 	      {
 | |
| 		dest.append(symbols.getGroupingSeparator(), NumberFormat.Field.GROUPING_SEPARATOR);
 | |
| 		dest.setDefaultAttribute(NumberFormat.Field.INTEGER);
 | |
| 	      }
 | |
| 	    dest.append((char) (zeroStart + dig));
 | |
| 
 | |
| 	    groupPosition--;
 | |
| 	  }
 | |
| 	dest.setDefaultAttribute(null);
 | |
| 
 | |
| 	integerEndIndex = dest.length();
 | |
| 	   
 | |
| 	int decimal_index = integerEndIndex;
 | |
| 	int consecutive_zeros = 0;
 | |
| 	int total_digits = 0;
 | |
| 
 | |
| 	int localMaximumFractionDigits = maximumFractionDigits;
 | |
| 
 | |
| 	if (useExponentialNotation)
 | |
| 	  localMaximumFractionDigits += minimumIntegerDigits - count;
 | |
| 
 | |
| 	// Strip integer part from NUMBER.
 | |
| 	double fracPart = baseNumber - Math.floor(baseNumber);
 | |
| 	
 | |
| 	if ( ((fracPart != 0 || minimumFractionDigits > 0) && localMaximumFractionDigits > 0)
 | |
| 	     || decimalSeparatorAlwaysShown)
 | |
| 	  {
 | |
| 	    dest.append (symbols.getDecimalSeparator(), NumberFormat.Field.DECIMAL_SEPARATOR);
 | |
| 	  }
 | |
| 
 | |
| 	int fraction_begin = dest.length();
 | |
| 	dest.setDefaultAttribute(NumberFormat.Field.FRACTION);
 | |
| 	for (count = 0;
 | |
| 	     count < localMaximumFractionDigits
 | |
| 	       && (fracPart != 0 || count < minimumFractionDigits);
 | |
| 	     ++count)
 | |
| 	  {
 | |
| 	    ++total_digits;
 | |
| 	    fracPart *= 10;
 | |
| 	    long dig = (long) fracPart;
 | |
| 	    if (dig == 0)
 | |
| 	      ++consecutive_zeros;
 | |
| 	    else
 | |
| 	      consecutive_zeros = 0;
 | |
| 	    dest.append((char) (symbols.getZeroDigit() + dig));
 | |
| 
 | |
| 	    // Strip integer part from FRACPART.
 | |
| 	    fracPart = fracPart - Math.floor (fracPart);
 | |
| 	  }
 | |
| 
 | |
| 	// Strip extraneous trailing `0's.  We can't always detect
 | |
| 	// these in the loop.
 | |
| 	int extra_zeros = Math.min (consecutive_zeros,
 | |
| 				    total_digits - minimumFractionDigits);
 | |
| 	if (extra_zeros > 0)
 | |
| 	  {
 | |
| 	    dest.cutTail(extra_zeros);
 | |
| 	    total_digits -= extra_zeros;
 | |
| 	    if (total_digits == 0 && !decimalSeparatorAlwaysShown)
 | |
| 	      dest.cutTail(1);
 | |
| 	  }
 | |
| 
 | |
| 	if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
 | |
| 	  {
 | |
| 	    fieldPos.setBeginIndex(fraction_begin);
 | |
| 	    fieldPos.setEndIndex(dest.length());
 | |
| 	  }
 | |
| 
 | |
| 	// Finally, print the exponent.
 | |
| 	if (useExponentialNotation)
 | |
| 	  {
 | |
| 	    dest.append(symbols.getExponential(), NumberFormat.Field.EXPONENT_SYMBOL);	    
 | |
| 	    if (exponent < 0)
 | |
| 	      {
 | |
| 		dest.append (symbols.getMinusSign (), NumberFormat.Field.EXPONENT_SIGN);
 | |
| 		exponent = - exponent;
 | |
| 	      }
 | |
| 	    index = dest.length();
 | |
| 	    dest.setDefaultAttribute(NumberFormat.Field.EXPONENT);
 | |
| 	    String exponentString = Long.toString ((long) exponent);
 | |
| 
 | |
| 	    for (count = 0; count < minExponentDigits-exponentString.length();
 | |
| 		 count++)
 | |
| 	      dest.append((char) symbols.getZeroDigit());
 | |
| 
 | |
| 	    for (count = 0;
 | |
| 		 count < exponentString.length();
 | |
| 		 ++count)
 | |
| 	      {
 | |
| 		int dig = exponentString.charAt(count);
 | |
| 		dest.append((char) (zeroStart + dig));
 | |
| 	      }
 | |
| 	  }
 | |
|       }
 | |
| 
 | |
|     if (fieldPos != null && 
 | |
| 	(fieldPos.getField() == INTEGER_FIELD ||
 | |
| 	 fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER))
 | |
|       {
 | |
| 	fieldPos.setBeginIndex(integerBeginIndex);
 | |
| 	fieldPos.setEndIndex(integerEndIndex);
 | |
|       }
 | |
| 		
 | |
|     if (is_neg && negativeSuffix != null)
 | |
|       {
 | |
| 	dest.append(substituteCurrency(negativeSuffix, number),
 | |
| 		    negativeSuffixRanges, negativeSuffixAttrs);
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	dest.append(substituteCurrency(positiveSuffix, number),
 | |
| 		    positiveSuffixRanges, positiveSuffixAttrs);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   public StringBuffer format (double number, StringBuffer dest,
 | |
| 			      FieldPosition fieldPos)
 | |
|   {
 | |
|     formatInternal (number, new StringFormatBuffer(dest), fieldPos);
 | |
|     return dest;
 | |
|   }
 | |
| 
 | |
|   public AttributedCharacterIterator formatToCharacterIterator (Object value)
 | |
|   {
 | |
|     AttributedFormatBuffer sbuf = new AttributedFormatBuffer();
 | |
| 
 | |
|     if (value instanceof Number)
 | |
|       formatInternal(((Number) value).doubleValue(), sbuf, null);
 | |
|     else
 | |
|       throw new IllegalArgumentException 
 | |
| 	("Cannot format given Object as a Number");
 | |
|     
 | |
|     sbuf.sync();
 | |
|     return new FormatCharacterIterator(sbuf.getBuffer().toString(), 
 | |
| 				       sbuf.getRanges(), 
 | |
| 				       sbuf.getAttributes());
 | |
|   }
 | |
| 
 | |
|   public StringBuffer format (long number, StringBuffer dest,
 | |
| 			      FieldPosition fieldPos)
 | |
|   {
 | |
|     // If using exponential notation, we just format as a double.
 | |
|     if (useExponentialNotation)
 | |
|        return format ((double) number, dest, fieldPos);
 | |
| 
 | |
|     boolean is_neg = number < 0;
 | |
|     if (is_neg)
 | |
|       {
 | |
| 	if (negativePrefix != null)
 | |
| 	  dest.append(substituteCurrency(negativePrefix, number));
 | |
| 	else
 | |
| 	  {
 | |
| 	    dest.append(symbols.getMinusSign());
 | |
| 	    dest.append(substituteCurrency(positivePrefix, number));
 | |
| 	  }
 | |
| 	number = - number;
 | |
|       }
 | |
|     else
 | |
|       dest.append(substituteCurrency(positivePrefix, number));
 | |
| 
 | |
|     int integerBeginIndex = dest.length();
 | |
|     int index = dest.length();
 | |
|     int count = 0;
 | |
| 
 | |
|     /* Handle percentages, etc. */
 | |
|     number *= multiplier;
 | |
|     while (count < maximumIntegerDigits
 | |
| 	   && (number > 0 || count < minimumIntegerDigits))
 | |
|       {
 | |
| 	long dig = number % 10;
 | |
| 	number /= 10;
 | |
| 	// NUMBER and DIG will be less than 0 if the original number
 | |
| 	// was the most negative long.
 | |
| 	if (dig < 0)
 | |
| 	  {
 | |
| 	    dig = - dig;
 | |
| 	    number = - number;
 | |
| 	  }
 | |
| 
 | |
| 	// Append group separator if required.
 | |
| 	if (groupingUsed && count > 0 && groupingSize != 0 && count % groupingSize == 0)
 | |
| 	  dest.insert(index, symbols.getGroupingSeparator());
 | |
| 
 | |
| 	dest.insert(index, (char) (symbols.getZeroDigit() + dig));
 | |
| 
 | |
| 	++count;
 | |
|       }
 | |
| 
 | |
|     if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD)
 | |
|       {
 | |
| 	fieldPos.setBeginIndex(integerBeginIndex);
 | |
| 	fieldPos.setEndIndex(dest.length());
 | |
|       }
 | |
| 
 | |
|     if (decimalSeparatorAlwaysShown || minimumFractionDigits > 0)
 | |
|       {
 | |
| 	dest.append(symbols.getDecimalSeparator());
 | |
| 	if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD)
 | |
| 	  {
 | |
| 	    fieldPos.setBeginIndex(dest.length());
 | |
| 	    fieldPos.setEndIndex(dest.length() + minimumFractionDigits);
 | |
| 	  }
 | |
|       }
 | |
| 
 | |
|     for (count = 0; count < minimumFractionDigits; ++count)
 | |
|       dest.append(symbols.getZeroDigit());
 | |
| 
 | |
|     dest.append((is_neg && negativeSuffix != null)
 | |
| 		? substituteCurrency(negativeSuffix, number)
 | |
| 		: substituteCurrency(positiveSuffix, number));
 | |
|     return dest;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the currency corresponding to the currency symbol stored
 | |
|    * in the instance of <code>DecimalFormatSymbols</code> used by this
 | |
|    * <code>DecimalFormat</code>.
 | |
|    *
 | |
|    * @return A new instance of <code>Currency</code> if
 | |
|    * the currency code matches a known one, null otherwise.
 | |
|    */
 | |
|   public Currency getCurrency()
 | |
|   {
 | |
|     return symbols.getCurrency();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a copy of the symbols used by this instance.
 | |
|    * 
 | |
|    * @return A copy of the symbols.
 | |
|    */
 | |
|   public DecimalFormatSymbols getDecimalFormatSymbols()
 | |
|   {
 | |
|     return (DecimalFormatSymbols) symbols.clone();
 | |
|   }
 | |
| 
 | |
|   public int getGroupingSize ()
 | |
|   {
 | |
|     return groupingSize;
 | |
|   }
 | |
| 
 | |
|   public int getMultiplier ()
 | |
|   {
 | |
|     return multiplier;
 | |
|   }
 | |
| 
 | |
|   public String getNegativePrefix ()
 | |
|   {
 | |
|     return negativePrefix;
 | |
|   }
 | |
| 
 | |
|   public String getNegativeSuffix ()
 | |
|   {
 | |
|     return negativeSuffix;
 | |
|   }
 | |
| 
 | |
|   public String getPositivePrefix ()
 | |
|   {
 | |
|     return positivePrefix;
 | |
|   }
 | |
| 
 | |
|   public String getPositiveSuffix ()
 | |
|   {
 | |
|     return positiveSuffix;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns a hash code for this object.
 | |
|    *
 | |
|    * @return A hash code.
 | |
|    */
 | |
|   public int hashCode()
 | |
|   {
 | |
|     return toPattern().hashCode();
 | |
|   }
 | |
| 
 | |
|   public boolean isDecimalSeparatorAlwaysShown ()
 | |
|   {
 | |
|     return decimalSeparatorAlwaysShown;
 | |
|   }
 | |
| 
 | |
|   public Number parse (String str, ParsePosition pos)
 | |
|   {
 | |
|     /*
 | |
|      * Our strategy is simple: copy the text into separate buffers: one for the int part,
 | |
|      * one for the fraction part and for the exponential part.
 | |
|      * We translate or omit locale-specific information.  
 | |
|      * If exponential is sufficiently big we merge the fraction and int part and
 | |
|      * remove the '.' and then we use Long to convert the number. In the other
 | |
|      * case, we use Double to convert the full number.
 | |
|      */
 | |
| 
 | |
|     boolean is_neg = false;
 | |
|     int index = pos.getIndex();
 | |
|     StringBuffer int_buf = new StringBuffer ();
 | |
|         
 | |
|     // We have to check both prefixes, because one might be empty.  We
 | |
|     // want to pick the longest prefix that matches.
 | |
|     boolean got_pos = str.startsWith(positivePrefix, index);
 | |
|     String np = (negativePrefix != null
 | |
| 		 ? negativePrefix
 | |
| 		 : positivePrefix + symbols.getMinusSign());
 | |
|     boolean got_neg = str.startsWith(np, index);
 | |
| 
 | |
|     if (got_pos && got_neg)
 | |
|       {
 | |
| 	// By checking this way, we preserve ambiguity in the case
 | |
| 	// where the negative format differs only in suffix.  We
 | |
| 	// check this again later.
 | |
| 	if (np.length() > positivePrefix.length())
 | |
| 	  {
 | |
| 	    is_neg = true;
 | |
| 	    index += np.length();
 | |
| 	  }
 | |
| 	else
 | |
| 	  index += positivePrefix.length();
 | |
|       }
 | |
|     else if (got_neg)
 | |
|       {
 | |
| 	is_neg = true;
 | |
| 	index += np.length();
 | |
|       }
 | |
|     else if (got_pos)
 | |
|       index += positivePrefix.length();
 | |
|     else
 | |
|       {
 | |
| 	pos.setErrorIndex (index);
 | |
| 	return null;
 | |
|       }
 | |
| 
 | |
|     // FIXME: handle Inf and NaN.
 | |
| 
 | |
|     // FIXME: do we have to respect minimum digits?
 | |
|     // What about multiplier?
 | |
| 
 | |
|     StringBuffer buf = int_buf;
 | |
|     StringBuffer frac_buf = null;
 | |
|     StringBuffer exp_buf = null;
 | |
|     int start_index = index;
 | |
|     int max = str.length();
 | |
|     int exp_index = -1;
 | |
|     int last = index + maximumIntegerDigits; 
 | |
| 
 | |
|     if (maximumFractionDigits > 0)
 | |
|       last += maximumFractionDigits + 1;
 | |
|     
 | |
|     if (useExponentialNotation)
 | |
|       last += minExponentDigits + 1;
 | |
| 
 | |
|     if (last > 0 && max > last)
 | |
|       max = last;
 | |
| 
 | |
|     char zero = symbols.getZeroDigit();
 | |
|     int last_group = -1;
 | |
|     boolean int_part = true;
 | |
|     boolean exp_part = false;
 | |
|     for (; index < max; ++index)
 | |
|       {
 | |
| 	char c = str.charAt(index);
 | |
| 
 | |
| 	// FIXME: what about grouping size?
 | |
| 	if (groupingUsed && c == symbols.getGroupingSeparator())
 | |
| 	  {
 | |
| 	    if (last_group != -1 
 | |
| 		&& groupingSize != 0  
 | |
| 		&& (index - last_group) % groupingSize != 0)
 | |
| 	      {
 | |
| 		pos.setErrorIndex(index);
 | |
| 		return null;
 | |
| 	      }
 | |
| 	    last_group = index+1;
 | |
| 	  }
 | |
| 	else if (c >= zero && c <= zero + 9)
 | |
| 	  {
 | |
| 	    buf.append((char) (c - zero + '0'));
 | |
| 	  }
 | |
| 	else if (parseIntegerOnly)
 | |
| 	  break;
 | |
| 	else if (c == symbols.getDecimalSeparator())
 | |
| 	  {
 | |
| 	    if (last_group != -1 
 | |
| 		&& groupingSize != 0 
 | |
| 		&& (index - last_group) % groupingSize != 0)
 | |
| 	      {
 | |
| 		pos.setErrorIndex(index);
 | |
| 		return null;
 | |
| 	      }
 | |
| 	    buf = frac_buf = new StringBuffer();
 | |
| 	    frac_buf.append('.');
 | |
| 	    int_part = false;
 | |
| 	  }
 | |
| 	else if (c == symbols.getExponential())
 | |
| 	  {
 | |
| 	    buf = exp_buf = new StringBuffer();
 | |
| 	    int_part = false;
 | |
| 	    exp_part = true;
 | |
| 	    exp_index = index+1;
 | |
| 	  }
 | |
| 	else if (exp_part
 | |
| 		 && (c == '+' || c == '-' || c == symbols.getMinusSign()))
 | |
| 	  {
 | |
| 	    // For exponential notation.
 | |
| 	    buf.append(c);
 | |
| 	  }
 | |
| 	else
 | |
| 	  break;
 | |
|       }
 | |
| 
 | |
|     if (index == start_index)
 | |
|       {
 | |
| 	// Didn't see any digits.
 | |
| 	pos.setErrorIndex(index);
 | |
| 	return null;
 | |
|       }
 | |
| 
 | |
|     // Check the suffix.  We must do this before converting the
 | |
|     // buffer to a number to handle the case of a number which is
 | |
|     // the most negative Long.
 | |
|     boolean got_pos_suf = str.startsWith(positiveSuffix, index);
 | |
|     String ns = (negativePrefix == null ? positiveSuffix : negativeSuffix);
 | |
|     boolean got_neg_suf = str.startsWith(ns, index);
 | |
|     if (is_neg)
 | |
|       {
 | |
| 	if (! got_neg_suf)
 | |
| 	  {
 | |
| 	    pos.setErrorIndex(index);
 | |
| 	    return null;
 | |
| 	  }
 | |
|       }
 | |
|     else if (got_pos && got_neg && got_neg_suf)
 | |
|       {
 | |
| 	is_neg = true;
 | |
|       }
 | |
|     else if (got_pos != got_pos_suf && got_neg != got_neg_suf)
 | |
|       {
 | |
| 	pos.setErrorIndex(index);
 | |
| 	return null;
 | |
|       }
 | |
|     else if (! got_pos_suf)
 | |
|       {
 | |
|        pos.setErrorIndex(index);
 | |
|        return null;
 | |
|       }
 | |
| 
 | |
|     String suffix = is_neg ? ns : positiveSuffix;
 | |
|     long parsedMultiplier = 1;
 | |
|     boolean use_long;
 | |
| 
 | |
|     if (is_neg)
 | |
|       int_buf.insert(0, '-');
 | |
| 
 | |
|     // Now handle the exponential part if there is one.
 | |
|     if (exp_buf != null)
 | |
|       {
 | |
| 	int exponent_value;
 | |
| 
 | |
| 	try
 | |
| 	  {
 | |
| 	    exponent_value = Integer.parseInt(exp_buf.toString());
 | |
| 	  }
 | |
| 	catch (NumberFormatException x1)
 | |
| 	  {
 | |
| 	    pos.setErrorIndex(exp_index);
 | |
| 	    return null;
 | |
| 	  }
 | |
| 
 | |
| 	if (frac_buf == null)
 | |
| 	  {
 | |
| 	    // We only have to add some zeros to the int part.
 | |
| 	    // Build a multiplier.
 | |
| 	    for (int i = 0; i < exponent_value; i++)
 | |
| 	      int_buf.append('0');
 | |
| 	    
 | |
| 	    use_long = true;
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    boolean long_sufficient;
 | |
| 
 | |
| 	    if (exponent_value < frac_buf.length()-1)
 | |
| 	      {
 | |
| 		int lastNonNull = -1;
 | |
| 		/* We have to check the fraction buffer: it may only be full of '0'
 | |
| 		 * or be sufficiently filled with it to convert the number into Long.
 | |
| 		 */
 | |
| 		for (int i = 1; i < frac_buf.length(); i++)
 | |
| 		  if (frac_buf.charAt(i) != '0')
 | |
| 		    lastNonNull = i;
 | |
| 
 | |
| 		long_sufficient = (lastNonNull < 0 || lastNonNull <= exponent_value);
 | |
| 	      }
 | |
| 	    else
 | |
| 	      long_sufficient = true;
 | |
| 	    
 | |
| 	    if (long_sufficient)
 | |
| 	      {
 | |
| 		for (int i = 1; i < frac_buf.length() && i < exponent_value; i++)
 | |
| 		  int_buf.append(frac_buf.charAt(i));
 | |
| 		for (int i = frac_buf.length()-1; i < exponent_value; i++)
 | |
| 		  int_buf.append('0');
 | |
| 		use_long = true;
 | |
| 	      }
 | |
| 	    else
 | |
| 	      {
 | |
| 		/*
 | |
| 		 * A long type is not sufficient, we build the full buffer to
 | |
| 		 * be parsed by Double.
 | |
| 		 */
 | |
| 		int_buf.append(frac_buf);
 | |
| 		int_buf.append('E');
 | |
| 		int_buf.append(exp_buf);
 | |
| 		use_long = false;
 | |
| 	      }
 | |
| 	  }
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	if (frac_buf != null)
 | |
| 	  {
 | |
| 	    /* Check whether the fraction buffer contains only '0' */
 | |
| 	    int i;
 | |
| 	    for (i = 1; i < frac_buf.length(); i++)
 | |
| 	      if (frac_buf.charAt(i) != '0')
 | |
| 		break;
 | |
| 	   
 | |
| 	    if (i != frac_buf.length())
 | |
| 	      {
 | |
| 		use_long = false;
 | |
| 		int_buf.append(frac_buf);
 | |
| 	      }
 | |
| 	    else
 | |
| 	      use_long = true;
 | |
| 	  }
 | |
| 	else
 | |
| 	  use_long = true;
 | |
|       }
 | |
| 
 | |
|     String t = int_buf.toString();
 | |
|     Number result = null;
 | |
|     if (use_long)
 | |
|       {
 | |
| 	try
 | |
| 	  {
 | |
| 	    result = new Long (t);
 | |
| 	  }
 | |
| 	catch (NumberFormatException x1)
 | |
| 	  {
 | |
| 	  }
 | |
|       }
 | |
|     else
 | |
|       {
 | |
| 	try
 | |
| 	  {
 | |
| 	    result = new Double (t);
 | |
| 	  }
 | |
| 	catch (NumberFormatException x2)
 | |
| 	  {
 | |
| 	  }
 | |
|       }
 | |
|     if (result == null)
 | |
|       {
 | |
| 	pos.setErrorIndex(index);
 | |
| 	return null;
 | |
|       }
 | |
| 
 | |
|     pos.setIndex(index + suffix.length());
 | |
| 
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the <code>Currency</code> on the
 | |
|    * <code>DecimalFormatSymbols</code> used, which also sets the
 | |
|    * currency symbols on those symbols.
 | |
|    */
 | |
|   public void setCurrency(Currency currency)
 | |
|   {
 | |
|     symbols.setCurrency(currency);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Sets the symbols used by this instance.  This method makes a copy of 
 | |
|    * the supplied symbols.
 | |
|    * 
 | |
|    * @param newSymbols  the symbols (<code>null</code> not permitted).
 | |
|    */
 | |
|   public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols)
 | |
|   {
 | |
|     symbols = (DecimalFormatSymbols) newSymbols.clone();
 | |
|   }
 | |
| 
 | |
|   public void setDecimalSeparatorAlwaysShown (boolean newValue)
 | |
|   {
 | |
|     decimalSeparatorAlwaysShown = newValue;
 | |
|   }
 | |
| 
 | |
|   public void setGroupingSize (int groupSize)
 | |
|   {
 | |
|     groupingSize = (byte) groupSize;
 | |
|   }
 | |
| 
 | |
|   public void setMaximumFractionDigits (int newValue)
 | |
|   {
 | |
|     super.setMaximumFractionDigits(Math.min(newValue, 340));
 | |
|   }
 | |
| 
 | |
|   public void setMaximumIntegerDigits (int newValue)
 | |
|   {
 | |
|     super.setMaximumIntegerDigits(Math.min(newValue, 309));
 | |
|   }
 | |
| 
 | |
|   public void setMinimumFractionDigits (int newValue)
 | |
|   {
 | |
|     super.setMinimumFractionDigits(Math.min(newValue, 340));
 | |
|   }
 | |
| 
 | |
|   public void setMinimumIntegerDigits (int newValue)
 | |
|   {
 | |
|     super.setMinimumIntegerDigits(Math.min(newValue, 309));
 | |
|   }
 | |
| 
 | |
|   public void setMultiplier (int newValue)
 | |
|   {
 | |
|     multiplier = newValue;
 | |
|   }
 | |
| 
 | |
|   public void setNegativePrefix (String newValue)
 | |
|   {
 | |
|     negativePrefix = newValue;
 | |
|   }
 | |
| 
 | |
|   public void setNegativeSuffix (String newValue)
 | |
|   {
 | |
|     negativeSuffix = newValue;
 | |
|   }
 | |
| 
 | |
|   public void setPositivePrefix (String newValue)
 | |
|   {
 | |
|     positivePrefix = newValue;
 | |
|   }
 | |
| 
 | |
|   public void setPositiveSuffix (String newValue)
 | |
|   {
 | |
|     positiveSuffix = newValue;
 | |
|   }
 | |
| 
 | |
|   private void quoteFix(StringBuffer buf, String text, String patChars)
 | |
|   {
 | |
|     int len = text.length();
 | |
|     for (int index = 0; index < len; ++index)
 | |
|       {
 | |
| 	char c = text.charAt(index);
 | |
| 	if (patChars.indexOf(c) != -1)
 | |
| 	  {
 | |
| 	    buf.append('\'');
 | |
| 	    buf.append(c);
 | |
| 	    buf.append('\'');
 | |
| 	  }
 | |
| 	else
 | |
| 	  buf.append(c);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   private String computePattern(DecimalFormatSymbols syms)
 | |
|   {
 | |
|     StringBuffer mainPattern = new StringBuffer ();
 | |
|     // We have to at least emit a zero for the minimum number of
 | |
|     // digits.  Past that we need hash marks up to the grouping
 | |
|     // separator (and one beyond).
 | |
|     int total_digits = Math.max(minimumIntegerDigits,
 | |
| 				groupingUsed ? groupingSize + 1: groupingSize);
 | |
|     for (int i = 0; i < total_digits - minimumIntegerDigits; ++i)
 | |
|       mainPattern.append(syms.getDigit());
 | |
|     for (int i = total_digits - minimumIntegerDigits; i < total_digits; ++i)
 | |
|       mainPattern.append(syms.getZeroDigit());
 | |
|     // Inserting the gropuing operator afterwards is easier.
 | |
|     if (groupingUsed)
 | |
|       mainPattern.insert(mainPattern.length() - groupingSize,
 | |
| 			 syms.getGroupingSeparator());
 | |
|     // See if we need decimal info.
 | |
|     if (minimumFractionDigits > 0 || maximumFractionDigits > 0
 | |
| 	|| decimalSeparatorAlwaysShown)
 | |
|       mainPattern.append(syms.getDecimalSeparator());
 | |
|     for (int i = 0; i < minimumFractionDigits; ++i)
 | |
|       mainPattern.append(syms.getZeroDigit());
 | |
|     for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i)
 | |
|       mainPattern.append(syms.getDigit());
 | |
|     if (useExponentialNotation)
 | |
|       {
 | |
| 	mainPattern.append(syms.getExponential());
 | |
| 	for (int i = 0; i < minExponentDigits; ++i)
 | |
| 	  mainPattern.append(syms.getZeroDigit());
 | |
| 	if (minExponentDigits == 0)
 | |
| 	  mainPattern.append(syms.getDigit());
 | |
|       }
 | |
| 
 | |
|     String main = mainPattern.toString();
 | |
|     String patChars = patternChars (syms);
 | |
|     mainPattern.setLength(0);
 | |
| 
 | |
|     quoteFix (mainPattern, positivePrefix, patChars);
 | |
|     mainPattern.append(main);
 | |
|     quoteFix (mainPattern, positiveSuffix, patChars);
 | |
| 
 | |
|     if (negativePrefix != null)
 | |
|       {
 | |
| 	quoteFix (mainPattern, negativePrefix, patChars);
 | |
| 	mainPattern.append(main);
 | |
| 	quoteFix (mainPattern, negativeSuffix, patChars);
 | |
|       }
 | |
| 
 | |
|     return mainPattern.toString();
 | |
|   }
 | |
| 
 | |
|   public String toLocalizedPattern ()
 | |
|   {
 | |
|     return computePattern (symbols);
 | |
|   }
 | |
| 
 | |
|   public String toPattern ()
 | |
|   {
 | |
|     return computePattern (nonLocalizedSymbols);
 | |
|   }
 | |
| 
 | |
|   private static final int MAXIMUM_INTEGER_DIGITS = 309; 
 | |
| 
 | |
|   // These names are fixed by the serialization spec.
 | |
|   private boolean decimalSeparatorAlwaysShown;
 | |
|   private byte groupingSize;
 | |
|   private byte minExponentDigits;
 | |
|   private int exponentRound;
 | |
|   private int multiplier;
 | |
|   private String negativePrefix;
 | |
|   private String negativeSuffix;
 | |
|   private String positivePrefix;
 | |
|   private String positiveSuffix;
 | |
|   private int[] negativePrefixRanges, positivePrefixRanges;
 | |
|   private HashMap[] negativePrefixAttrs, positivePrefixAttrs;
 | |
|   private int[] negativeSuffixRanges, positiveSuffixRanges;
 | |
|   private HashMap[] negativeSuffixAttrs, positiveSuffixAttrs;
 | |
|   private int serialVersionOnStream = 1;
 | |
|   private DecimalFormatSymbols symbols;
 | |
|   private boolean useExponentialNotation;
 | |
|   private static final long serialVersionUID = 864413376551465018L;
 | |
| 
 | |
|   private void readObject(ObjectInputStream stream)
 | |
|     throws IOException, ClassNotFoundException
 | |
|   {
 | |
|     stream.defaultReadObject();
 | |
|     if (serialVersionOnStream < 1)
 | |
|       {
 | |
|         useExponentialNotation = false;
 | |
| 	serialVersionOnStream = 1;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   // The locale-independent pattern symbols happen to be the same as
 | |
|   // the US symbols.
 | |
|   private static final DecimalFormatSymbols nonLocalizedSymbols
 | |
|     = new DecimalFormatSymbols (Locale.US);
 | |
| 
 | |
|   /**
 | |
|    * <p>
 | |
|    * Substitutes the currency symbol into the given string,
 | |
|    * based on the value used.  Currency symbols can either
 | |
|    * be a simple series of characters (e.g. '$'), which are
 | |
|    * simply used as is, or they can be of a more complex
 | |
|    * form:
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * (lower bound)|(mid value)|(upper bound)
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * where each bound has the syntax '(value)(# or <)(symbol)',
 | |
|    * to indicate the bounding value and the symbol used.
 | |
|    * </p>
 | |
|    * <p>
 | |
|    * The currency symbol replaces the currency specifier, '\u00a4',
 | |
|    * an unlocalised character, which thus is used as such in all formats.
 | |
|    * If this symbol occurs twice, the international currency code is used
 | |
|    * instead.
 | |
|    * </p>
 | |
|    *
 | |
|    * @param string The string containing the currency specifier, '\u00a4'.
 | |
|    * @param number the number being formatted.
 | |
|    * @return a string formatted for the correct currency.
 | |
|    */
 | |
|   private String substituteCurrency(String string, double number)
 | |
|   {
 | |
|     int index;
 | |
|     int length;
 | |
|     char currentChar;
 | |
|     StringBuffer buf;
 | |
|     
 | |
|     index = 0;
 | |
|     length = string.length();
 | |
|     buf = new StringBuffer();
 | |
|     
 | |
|     while (index < length)
 | |
|       {
 | |
| 	currentChar = string.charAt(index);
 | |
| 	if (string.charAt(index) == '\u00a4')
 | |
| 	  {
 | |
| 	    if ((index + 1) < length && string.charAt(index + 1) == '\u00a4')
 | |
| 	      {
 | |
| 		buf.append(symbols.getInternationalCurrencySymbol());
 | |
| 		index += 2;
 | |
| 	      }
 | |
| 	    else
 | |
| 	      {
 | |
| 		String symbol;
 | |
| 		
 | |
| 		symbol = symbols.getCurrencySymbol();
 | |
| 		if (symbol.startsWith("="))
 | |
| 		  {
 | |
| 		    String[] bounds;
 | |
| 		    int[] boundValues;
 | |
| 		    String[] boundSymbols;
 | |
| 		    
 | |
| 		    bounds = symbol.substring(1).split("\\|");
 | |
| 		    boundValues = new int[3];
 | |
| 		    boundSymbols = new String[3];
 | |
| 		    for (int a = 0; a < 3; ++a)
 | |
| 		      {
 | |
| 			String[] bound;
 | |
| 			
 | |
| 			bound = bounds[a].split("[#<]");
 | |
| 			boundValues[a] = Integer.parseInt(bound[0]);
 | |
| 			boundSymbols[a] = bound[1];
 | |
| 		      }
 | |
| 		    if (number <= boundValues[0])
 | |
| 		      {
 | |
| 			buf.append(boundSymbols[0]);
 | |
| 		      }
 | |
| 		    else if (number >= boundValues[2])
 | |
| 		      {
 | |
| 			buf.append(boundSymbols[2]);
 | |
| 		      }
 | |
| 		    else 
 | |
| 		      {
 | |
| 			buf.append(boundSymbols[1]);
 | |
| 		      }
 | |
| 		    ++index;
 | |
| 		  }
 | |
| 		else
 | |
| 		  {
 | |
| 		    buf.append(symbol);
 | |
| 		    ++index;
 | |
| 		  }
 | |
| 	      }
 | |
| 	  }
 | |
| 	else
 | |
| 	  {
 | |
| 	    buf.append(string.charAt(index));
 | |
| 	    ++index;
 | |
| 	  }
 | |
|       }
 | |
|     return buf.toString();
 | |
|   }
 | |
|   
 | |
| }
 |