| // DecimalFormat.java - Localized number formatting. |
| |
| /* Copyright (C) 1999, 2000 Free Software Foundation |
| |
| This file is part of libgcj. |
| |
| This software is copyrighted work licensed under the terms of the |
| Libgcj License. Please consult the file "LIBGCJ_LICENSE" for |
| details. */ |
| |
| package java.text; |
| |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import java.io.ObjectInputStream; |
| import java.io.IOException; |
| |
| /** |
| * @author Tom Tromey <tromey@cygnus.com> |
| * @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 final int scanFix (String pattern, int index, StringBuffer buf, |
| String patChars, DecimalFormatSymbols syms, |
| boolean is_suffix) |
| { |
| int len = pattern.length(); |
| buf.setLength(0); |
| boolean multiplierSet = false; |
| while (index < len) |
| { |
| char c = pattern.charAt(index); |
| if (c == '\'' && index + 1 < len |
| && pattern.charAt(index + 1) == '\'') |
| { |
| buf.append(c); |
| ++index; |
| } |
| else if (c == '\'' && index + 2 < len |
| && pattern.charAt(index + 2) == '\'') |
| { |
| buf.append(pattern.charAt(index + 1)); |
| index += 2; |
| } |
| else if (c == '\u00a4') |
| { |
| if (index + 1 < len && pattern.charAt(index + 1) == '\u00a4') |
| { |
| buf.append(syms.getInternationalCurrencySymbol()); |
| ++index; |
| } |
| else |
| buf.append(syms.getCurrencySymbol()); |
| } |
| else if (is_suffix && c == syms.getPercent()) |
| { |
| if (multiplierSet) |
| throw new IllegalArgumentException ("multiplier already set " + |
| "- index: " + index); |
| multiplierSet = true; |
| multiplier = 100; |
| buf.append(c); |
| } |
| else if (is_suffix && c == syms.getPerMill()) |
| { |
| if (multiplierSet) |
| throw new IllegalArgumentException ("multiplier already set " + |
| "- index: " + index); |
| multiplierSet = true; |
| multiplier = 1000; |
| buf.append(c); |
| } |
| else if (patChars.indexOf(c) != -1) |
| { |
| // This is a pattern character. |
| break; |
| } |
| else |
| buf.append(c); |
| ++index; |
| } |
| |
| return index; |
| } |
| |
| // A helper which reads a number format. |
| private final 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; |
| 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() |
| && 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; |
| } |
| } |
| |
| return index; |
| } |
| |
| // This helper function creates a string consisting of all the |
| // characters which can appear in a pattern and must be quoted. |
| private final 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 final 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 = 309; |
| minimumFractionDigits = 0; |
| minimumIntegerDigits = 1; |
| |
| StringBuffer buf = new StringBuffer (); |
| String patChars = patternChars (syms); |
| |
| int max = pattern.length(); |
| int index = scanFix (pattern, 0, buf, patChars, syms, false); |
| positivePrefix = buf.toString(); |
| |
| index = scanFormat (pattern, index, patChars, syms, true); |
| |
| index = scanFix (pattern, index, buf, patChars, syms, true); |
| positiveSuffix = buf.toString(); |
| |
| 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); |
| negativePrefix = buf.toString(); |
| |
| // 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); |
| negativeSuffix = buf.toString(); |
| |
| 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 () |
| { |
| return new DecimalFormat (this); |
| } |
| |
| private DecimalFormat (DecimalFormat dup) |
| { |
| decimalSeparatorAlwaysShown = dup.decimalSeparatorAlwaysShown; |
| groupingSize = dup.groupingSize; |
| minExponentDigits = dup.minExponentDigits; |
| multiplier = dup.multiplier; |
| negativePrefix = dup.negativePrefix; |
| negativeSuffix = dup.negativeSuffix; |
| positivePrefix = dup.positivePrefix; |
| positiveSuffix = dup.positiveSuffix; |
| symbols = (DecimalFormatSymbols) dup.symbols.clone(); |
| useExponentialNotation = dup.useExponentialNotation; |
| } |
| |
| public DecimalFormat () |
| { |
| this ("#,##0.###"); |
| } |
| |
| public DecimalFormat (String pattern) |
| { |
| this (pattern, new DecimalFormatSymbols ()); |
| } |
| |
| public DecimalFormat (String pattern, DecimalFormatSymbols symbols) |
| { |
| this.symbols = symbols; |
| applyPattern (pattern); |
| } |
| |
| private final boolean equals (String s1, String s2) |
| { |
| if (s1 == null || s2 == null) |
| return s1 == s2; |
| return s1.equals(s2); |
| } |
| |
| public boolean equals (Object obj) |
| { |
| if (! (obj instanceof DecimalFormat)) |
| return false; |
| DecimalFormat dup = (DecimalFormat) obj; |
| return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown |
| && groupingSize == dup.groupingSize |
| && minExponentDigits == dup.minExponentDigits |
| && multiplier == dup.multiplier |
| && equals(negativePrefix, dup.negativePrefix) |
| && equals(negativeSuffix, dup.negativeSuffix) |
| && equals(positivePrefix, dup.positivePrefix) |
| && equals(positiveSuffix, dup.positiveSuffix) |
| && symbols.equals(dup.symbols) |
| && useExponentialNotation == dup.useExponentialNotation); |
| } |
| |
| public StringBuffer format (double number, StringBuffer dest, |
| FieldPosition fieldPos) |
| { |
| // A very special case. |
| if (Double.isNaN(number)) |
| { |
| dest.append(symbols.getNaN()); |
| if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD) |
| { |
| int index = dest.length(); |
| fieldPos.setBeginIndex(index - symbols.getNaN().length()); |
| fieldPos.setEndIndex(index); |
| } |
| return dest; |
| } |
| |
| boolean is_neg = number < 0; |
| if (is_neg) |
| { |
| if (negativePrefix != null) |
| dest.append(negativePrefix); |
| else |
| { |
| dest.append(symbols.getMinusSign()); |
| dest.append(positivePrefix); |
| } |
| number = - number; |
| } |
| else |
| dest.append(positivePrefix); |
| |
| int integerBeginIndex = dest.length(); |
| int integerEndIndex = 0; |
| if (Double.isInfinite (number)) |
| { |
| dest.append(symbols.getInfinity()); |
| integerEndIndex = dest.length(); |
| } |
| else |
| { |
| number *= multiplier; |
| |
| // Compute exponent. |
| long exponent = 0; |
| double baseNumber; |
| if (useExponentialNotation) |
| { |
| exponent = (long) (Math.log(number) / Math.log(10)); |
| if (minimumIntegerDigits > 0) |
| exponent -= minimumIntegerDigits - 1; |
| baseNumber = (long) (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); |
| int count = 0; |
| while (count < maximumIntegerDigits |
| && (intPart > 0 || count < minimumIntegerDigits)) |
| { |
| long dig = (long) (intPart % 10); |
| intPart = Math.floor(intPart / 10); |
| |
| // Append group separator if required. |
| if (groupingUsed && count > 0 && count % groupingSize == 0) |
| dest.insert(index, symbols.getGroupingSeparator()); |
| |
| dest.insert(index, (char) (symbols.getZeroDigit() + dig)); |
| |
| ++count; |
| } |
| |
| integerEndIndex = dest.length(); |
| |
| int decimal_index = integerEndIndex; |
| int consecutive_zeros = 0; |
| int total_digits = 0; |
| |
| // Strip integer part from NUMBER. |
| double fracPart = baseNumber - Math.floor(baseNumber); |
| for (count = 0; |
| count < maximumFractionDigits |
| && (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.setLength(dest.length() - extra_zeros); |
| total_digits -= extra_zeros; |
| } |
| |
| // If required, add the decimal symbol. |
| if (decimalSeparatorAlwaysShown |
| || total_digits > 0) |
| { |
| dest.insert(decimal_index, symbols.getDecimalSeparator()); |
| if (fieldPos != null && fieldPos.getField() == FRACTION_FIELD) |
| { |
| fieldPos.setBeginIndex(decimal_index + 1); |
| fieldPos.setEndIndex(dest.length()); |
| } |
| } |
| |
| // Finally, print the exponent. |
| if (useExponentialNotation) |
| { |
| dest.append(symbols.getExponential()); |
| dest.append(exponent < 0 ? '-' : '+'); |
| index = dest.length(); |
| for (count = 0; |
| exponent > 0 || count < minExponentDigits; |
| ++count) |
| { |
| long dig = exponent % 10; |
| exponent /= 10; |
| dest.insert(index, (char) (symbols.getZeroDigit() + dig)); |
| } |
| } |
| } |
| |
| if (fieldPos != null && fieldPos.getField() == INTEGER_FIELD) |
| { |
| fieldPos.setBeginIndex(integerBeginIndex); |
| fieldPos.setEndIndex(integerEndIndex); |
| } |
| |
| dest.append((is_neg && negativeSuffix != null) |
| ? negativeSuffix |
| : positiveSuffix); |
| return dest; |
| } |
| |
| 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(negativePrefix); |
| else |
| { |
| dest.append(symbols.getMinusSign()); |
| dest.append(positivePrefix); |
| } |
| number = - number; |
| } |
| else |
| dest.append(positivePrefix); |
| |
| int integerBeginIndex = dest.length(); |
| int index = dest.length(); |
| int count = 0; |
| 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 && 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) |
| ? negativeSuffix |
| : positiveSuffix); |
| return dest; |
| } |
| |
| public DecimalFormatSymbols getDecimalFormatSymbols () |
| { |
| return symbols; |
| } |
| |
| 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; |
| } |
| |
| public int hashCode () |
| { |
| int hash = (negativeSuffix.hashCode() ^ negativePrefix.hashCode() |
| ^positivePrefix.hashCode() ^ positiveSuffix.hashCode()); |
| // FIXME. |
| return hash; |
| } |
| |
| public boolean isDecimalSeparatorAlwaysShown () |
| { |
| return decimalSeparatorAlwaysShown; |
| } |
| |
| public Number parse (String str, ParsePosition pos) |
| { |
| // Our strategy is simple: copy the text into a buffer, |
| // translating or omitting locale-specific information. Then |
| // let Double or Long convert the number for us. |
| |
| boolean is_neg = false; |
| int index = pos.getIndex(); |
| StringBuffer 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/maxmimum digit stuff? |
| // What about leading zeros? What about multiplier? |
| |
| int start_index = index; |
| int max = str.length(); |
| 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 |
| && (index - last_group) % groupingSize != 0) |
| { |
| pos.setErrorIndex(index); |
| return null; |
| } |
| last_group = index; |
| } |
| else if (c >= zero && c <= zero + 9) |
| { |
| buf.append((char) (c - zero + '0')); |
| exp_part = false; |
| } |
| else if (parseIntegerOnly) |
| break; |
| else if (c == symbols.getDecimalSeparator()) |
| { |
| if (last_group != -1 |
| && (index - last_group) % groupingSize != 0) |
| { |
| pos.setErrorIndex(index); |
| return null; |
| } |
| buf.append('.'); |
| int_part = false; |
| } |
| else if (c == symbols.getExponential()) |
| { |
| buf.append('E'); |
| int_part = false; |
| exp_part = true; |
| } |
| 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; |
| } |
| |
| String suffix = is_neg ? ns : positiveSuffix; |
| if (is_neg) |
| buf.insert(0, '-'); |
| |
| String t = buf.toString(); |
| Number result = null; |
| try |
| { |
| result = new Long (t); |
| } |
| catch (NumberFormatException x1) |
| { |
| try |
| { |
| result = new Double (t); |
| } |
| catch (NumberFormatException x2) |
| { |
| } |
| } |
| if (result == null) |
| { |
| pos.setErrorIndex(index); |
| return null; |
| } |
| |
| pos.setIndex(index + suffix.length()); |
| |
| return result; |
| } |
| |
| public void setDecimalFormatSymbols (DecimalFormatSymbols newSymbols) |
| { |
| symbols = newSymbols; |
| } |
| |
| public void setDecimalSeparatorAlwaysShown (boolean newValue) |
| { |
| decimalSeparatorAlwaysShown = newValue; |
| } |
| |
| public void setGroupingSize (int groupSize) |
| { |
| groupingSize = (byte) groupSize; |
| } |
| |
| public void setMaximumFractionDigits (int newValue) |
| { |
| maximumFractionDigits = Math.min(newValue, 340); |
| } |
| |
| public void setMaximumIntegerDigits (int newValue) |
| { |
| maximumIntegerDigits = Math.min(newValue, 309); |
| } |
| |
| public void setMinimumFractionDigits (int newValue) |
| { |
| minimumFractionDigits = Math.min(newValue, 340); |
| } |
| |
| public void setMinimumIntegerDigits (int newValue) |
| { |
| minimumIntegerDigits = 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 final 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 final 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: 0); |
| 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); |
| } |
| |
| // These names are fixed by the serialization spec. |
| private boolean decimalSeparatorAlwaysShown; |
| private byte groupingSize; |
| private byte minExponentDigits; |
| private int multiplier; |
| private String negativePrefix; |
| private String negativeSuffix; |
| private String positivePrefix; |
| private String positiveSuffix; |
| 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); |
| } |