You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gh...@apache.org on 2006/07/13 14:42:48 UTC
svn commit: r421603 [1/2] - in
/incubator/harmony/enhanced/classlib/trunk/modules/luni/src:
main/java/java/util/Formatter.java
test/java/tests/api/java/util/FormatterTest.java
Author: gharley
Date: Thu Jul 13 05:42:48 2006
New Revision: 421603
URL: http://svn.apache.org/viewvc?rev=421603&view=rev
Log:
HARMONY 865 : [luni] Implementation of java.util.Formatter formats Float, Double, BigDecimal data types
Modified:
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Formatter.java
incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/FormatterTest.java
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Formatter.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Formatter.java?rev=421603&r1=421602&r2=421603&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Formatter.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Formatter.java Thu Jul 13 05:42:48 2006
@@ -25,17 +25,17 @@
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.DateFormatSymbols;
+import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
-import org.apache.harmony.luni.util.NotYetImplementedException;
-
/**
* Formatter provides the method to give out formatted string just like the
* printf-style. Layout,alignment and other format flags are provided to format
@@ -600,6 +600,10 @@
static final int LAST_ARGUMENT_INDEX = -2;
static final int UNSET = -1;
+
+ static final int FLAGS_UNSET = 0;
+
+ static final int DEFAULT_PRECISION = 6;
static final int FLAG_MINUS = 1;
@@ -778,7 +782,7 @@
private Object arg;
- private Locale locale; // will be used in new feature.
+ private Locale locale;
private static String lineSeparator;
@@ -812,11 +816,11 @@
* argument.
*/
String transform(FormatToken formatToken,
- Object arg) {
+ Object argument) {
/* init data member to print */
this.formatToken = formatToken;
- this.arg = arg;
+ this.arg = argument;
String result;
switch (formatToken.getConversionType()) {
@@ -903,7 +907,7 @@
}
// only '-' is valid for flags
- if (0 != flags && FormatToken.FLAG_MINUS != flags) {
+ if (FormatToken.FLAGS_UNSET != flags && FormatToken.FLAG_MINUS != flags) {
throw new FormatFlagsConversionMismatchException(formatToken
.getStrFlags(), formatToken.getConversionType());
}
@@ -934,7 +938,7 @@
}
// only '-' is valid for flags
- if (0 != flags && FormatToken.FLAG_MINUS != flags) {
+ if (FormatToken.FLAGS_UNSET != flags && FormatToken.FLAG_MINUS != flags) {
throw new FormatFlagsConversionMismatchException(formatToken
.getStrFlags(), formatToken.getConversionType());
}
@@ -964,7 +968,7 @@
if (arg instanceof Formattable) {
int flag = 0;
// only minus and sharp flag is valid
- if (0 != (flags & ~FormatToken.FLAG_MINUS & ~FormatToken.FLAG_SHARP)) {
+ if (FormatToken.FLAGS_UNSET != (flags & ~FormatToken.FLAG_MINUS & ~FormatToken.FLAG_SHARP)) {
throw new IllegalFormatFlagsException(formatToken
.getStrFlags());
}
@@ -984,17 +988,16 @@
// returns null, which tells the Parser to add nothing to the
// output.
return null;
- } else {
- // only '-' is valid for flags if the argument is not an
- // instance of Formattable
- if (0 != flags && FormatToken.FLAG_MINUS != flags) {
- throw new FormatFlagsConversionMismatchException(
- formatToken.getStrFlags(), formatToken
- .getConversionType());
- }
-
- result.append(arg);
+ }
+ // only '-' is valid for flags if the argument is not an
+ // instance of Formattable
+ if (FormatToken.FLAGS_UNSET != flags && FormatToken.FLAG_MINUS != flags) {
+ throw new FormatFlagsConversionMismatchException(
+ formatToken.getStrFlags(), formatToken
+ .getConversionType());
}
+
+ result.append(arg);
return padding(result, startIndex);
}
@@ -1014,7 +1017,7 @@
}
// only '-' is valid for flags
- if (0 != flags && FormatToken.FLAG_MINUS != flags) {
+ if (FormatToken.FLAGS_UNSET != flags && FormatToken.FLAG_MINUS != flags) {
throw new FormatFlagsConversionMismatchException(formatToken
.getStrFlags().toString(), formatToken
.getConversionType());
@@ -1074,7 +1077,7 @@
+ formatToken.getConversionType());
}
- if (0 != flags && FormatToken.FLAG_MINUS != flags) {
+ if (FormatToken.FLAGS_UNSET != flags && FormatToken.FLAG_MINUS != flags) {
throw new FormatFlagsConversionMismatchException(formatToken
.getStrFlags(), formatToken.getConversionType());
}
@@ -1095,12 +1098,12 @@
.getPrecision());
}
- if (FormatToken.UNSET != formatToken.getWidth()) {
+ if (formatToken.isWidthSet()) {
throw new IllegalFormatWidthException(formatToken.getWidth());
}
int flags = formatToken.getFlags();
- if (0 != flags) {
+ if (FormatToken.FLAGS_UNSET != flags) {
throw new IllegalFormatFlagsException(formatToken.getStrFlags()
.toString());
}
@@ -1170,6 +1173,7 @@
int startIndex = 0;
boolean isNegative = false;
StringBuilder result = new StringBuilder();
+ char currentConversionType = formatToken.getConversionType();
long value;
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
@@ -1200,7 +1204,7 @@
throw new IllegalFormatConversionException(formatToken
.getConversionType(), arg.getClass());
}
- if ('d' != formatToken.getConversionType()) {
+ if ('d' != currentConversionType) {
if (formatToken.isFlagSet(FormatToken.FLAG_ADD)
| formatToken.isFlagSet(FormatToken.FLAG_SPACE)
| formatToken.isFlagSet(FormatToken.FLAG_COMMA)
@@ -1212,11 +1216,11 @@
}
if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
- if ('d' == formatToken.getConversionType()) {
+ if ('d' == currentConversionType) {
throw new FormatFlagsConversionMismatchException(
formatToken.getStrFlags(), formatToken
.getConversionType());
- } else if ('o' == formatToken.getConversionType()) {
+ } else if ('o' == currentConversionType) {
result.append("0"); //$NON-NLS-1$
startIndex += 1;
} else {
@@ -1235,7 +1239,7 @@
isNegative = true;
}
- if ('d' == formatToken.getConversionType()) {
+ if ('d' == currentConversionType) {
NumberFormat numberFormat = getNumberFormat();
if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
numberFormat.setGroupingUsed(true);
@@ -1256,7 +1260,7 @@
value &= INT_MASK;
}
}
- if ('o' == formatToken.getConversionType()) {
+ if ('o' == currentConversionType) {
result.append(Long.toOctalString(value));
} else {
result.append(Long.toHexString(value));
@@ -1278,22 +1282,8 @@
/* pad paddingChar to the output */
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
- /*
- * add () to the output,if the value is negative and
- * formatToken.FLAG_PARENTHESIS is set.
- */
- StringBuilder buffer = new StringBuilder();
- result.deleteCharAt(0); // delete the '-'
- result.insert(0, '(');
- if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
- formatToken.setWidth(formatToken.getWidth() - 1);
- buffer.append(padding(result, 1));
- buffer.append(')');
- } else {
- result.append(')');
- buffer.append(padding(result, 0));
- }
- return buffer.toString();
+ result = wrapParentheses(result);
+ return result.toString();
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
@@ -1302,6 +1292,64 @@
return padding(result, startIndex);
}
+ /*
+ * add () to the output,if the value is negative and
+ * formatToken.FLAG_PARENTHESIS is set. 'result' is used as an
+ * in-out parameter.
+ */
+ private StringBuilder wrapParentheses(StringBuilder result) {
+ // delete the '-'
+ result.deleteCharAt(0);
+ result.insert(0, '(');
+ if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
+ formatToken.setWidth(formatToken.getWidth() - 1);
+ padding(result, 1);
+ result.append(')');
+ } else {
+ result.append(')');
+ padding(result, 0);
+ }
+ return result;
+ }
+
+ private String transformFromSpecialNumber() {
+ String source = null;
+
+ if (!(arg instanceof Number) || arg instanceof BigDecimal) {
+ return null;
+ }
+
+ Number number = (Number) arg;
+ double d = number.doubleValue();
+ if (Double.isNaN(d)) {
+ source = "NaN"; //$NON-NLS-1$
+ } else if (Double.isInfinite(d)) {
+ if (d >= 0) {
+ if (formatToken.isFlagSet(FormatToken.FLAG_ADD)) {
+ source = "+Infinity"; //$NON-NLS-1$
+ } else if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
+ source = " Infinity"; //$NON-NLS-1$
+ } else {
+ source = "Infinity"; //$NON-NLS-1$
+ }
+ } else {
+ if (formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
+ source = "(Infinity)"; //$NON-NLS-1$
+ } else {
+ source = "-Infinity"; //$NON-NLS-1$
+ }
+ }
+ }
+
+ if (null != source) {
+ formatToken.setPrecision(FormatToken.UNSET);
+ formatToken.setFlags(formatToken.getFlags()
+ & (~FormatToken.FLAG_ZERO));
+ source = padding(new StringBuilder(source), 0);
+ }
+ return source;
+ }
+
private String transformFromNull() {
formatToken.setFlags(formatToken.getFlags()
& (~FormatToken.FLAG_ZERO));
@@ -1399,22 +1447,8 @@
/* pad paddingChar to the output */
if (isNegative
&& formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
- /*
- * add () to the output,if the value is negative and
- * formatToken.FLAG_PARENTTHESIS is set.
- */
- StringBuilder buffer = new StringBuilder();
- result.deleteCharAt(0); // delete the '-'
- result.insert(0, '(');
- if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
- formatToken.setWidth(formatToken.getWidth() - 1);
- buffer.append(padding(result, 1));
- buffer.append(')');
- } else {
- result.append(')');
- buffer.append(padding(result, 0));
- }
- return buffer.toString();
+ result = wrapParentheses(result);
+ return result.toString();
}
if (isNegative && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
@@ -1422,12 +1456,316 @@
}
return padding(result, startIndex);
}
-
+
/*
* Transforms a Float,Double or BigDecimal to a formatted string.
*/
private String transformFromFloat() {
- throw new NotYetImplementedException();
+ StringBuilder result = new StringBuilder();
+ int startIndex = 0;
+ char currentConversionType = formatToken.getConversionType();
+
+ if (formatToken.isFlagSet(FormatToken.FLAG_MINUS | FormatToken.FLAG_ZERO)) {
+ if (!formatToken.isWidthSet()) {
+ throw new MissingFormatWidthException(formatToken
+ .getStrFlags());
+ }
+ }
+
+ if (formatToken.isFlagSet(FormatToken.FLAG_ADD)
+ && formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
+ throw new IllegalFormatFlagsException(formatToken.getStrFlags());
+ }
+
+ if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
+ && formatToken.isFlagSet(FormatToken.FLAG_ZERO)) {
+ throw new IllegalFormatFlagsException(formatToken.getStrFlags());
+ }
+
+ if ('e' == Character.toLowerCase(currentConversionType)) {
+ if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
+ throw new FormatFlagsConversionMismatchException(
+ formatToken.getStrFlags(), currentConversionType);
+ }
+ }
+
+ if ('g' == Character.toLowerCase(currentConversionType)) {
+ if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
+ throw new FormatFlagsConversionMismatchException(
+ formatToken.getStrFlags(), currentConversionType);
+ }
+ }
+
+ if ('a' == Character.toLowerCase(currentConversionType)) {
+ if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)
+ || formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
+ throw new FormatFlagsConversionMismatchException(
+ formatToken.getStrFlags(), currentConversionType);
+ }
+ }
+
+ if (null == arg) {
+ return transformFromNull();
+ }
+
+ if (!(arg instanceof Float || arg instanceof Double || arg instanceof BigDecimal)) {
+ throw new IllegalFormatConversionException(
+ currentConversionType, arg.getClass());
+ }
+
+ String specialNumberResult = transformFromSpecialNumber();
+ if (null != specialNumberResult) {
+ return specialNumberResult;
+ }
+
+ if ('a' != Character.toLowerCase(currentConversionType)) {
+ formatToken
+ .setPrecision(formatToken.isPrecisionSet() ? formatToken
+ .getPrecision()
+ : FormatToken.DEFAULT_PRECISION);
+ }
+ // output result
+ FloatUtil floatUtil = new FloatUtil(result, formatToken,
+ (DecimalFormat) NumberFormat.getInstance(locale), arg);
+ switch (currentConversionType) {
+ case 'e':
+ case 'E': {
+ floatUtil.transform_e();
+ break;
+ }
+ case 'f': {
+ floatUtil.transform_f();
+ break;
+ }
+ case 'g':
+ case 'G': {
+ floatUtil.transform_g();
+ break;
+ }
+ case 'a':
+ case 'A': {
+ floatUtil.transform_a();
+ break;
+ }
+ }
+
+ formatToken.setPrecision(FormatToken.UNSET);
+
+ if (getDecimalFormatSymbols().getMinusSign() == result.charAt(0)) {
+ if (formatToken.isFlagSet(FormatToken.FLAG_PARENTHESIS)) {
+ result = wrapParentheses(result);
+ return result.toString();
+ }
+ } else {
+ if (formatToken.isFlagSet(FormatToken.FLAG_SPACE)) {
+ result.insert(0, ' ');
+ startIndex++;
+ }
+ if (formatToken.isFlagSet(FormatToken.FLAG_ADD)) {
+ result.insert(0, floatUtil.getAddSign());
+ startIndex++;
+ }
+ }
+
+ char firstChar = result.charAt(0);
+ if (formatToken.isFlagSet(FormatToken.FLAG_ZERO)
+ && (firstChar == floatUtil.getAddSign() || firstChar == floatUtil
+ .getMinusSign())) {
+ startIndex = 1;
+ }
+
+ if ('a' == Character.toLowerCase(currentConversionType)) {
+ startIndex += 2;
+ }
+ return padding(result, startIndex);
+ }
+
+ private static class FloatUtil {
+ private StringBuilder result;
+
+ private DecimalFormat decimalFormat;
+
+ private FormatToken formatToken;
+
+ private Object argument;
+
+ private char minusSign;
+
+ FloatUtil(StringBuilder result, FormatToken formatToken,
+ DecimalFormat decimalFormat, Object argument) {
+ this.result = result;
+ this.formatToken = formatToken;
+ this.decimalFormat = decimalFormat;
+ this.argument = argument;
+ this.minusSign = decimalFormat.getDecimalFormatSymbols()
+ .getMinusSign();
+ }
+
+ char getMinusSign() {
+ return minusSign;
+ }
+
+ char getAddSign() {
+ return '+';
+ }
+
+ void transform_e() {
+ StringBuilder pattern = new StringBuilder();
+ pattern.append('0');
+ if (formatToken.getPrecision() > 0) {
+ pattern.append('.');
+ char[] zeros = new char[formatToken.getPrecision()];
+ Arrays.fill(zeros, '0');
+ pattern.append(zeros);
+ }
+ pattern.append('E');
+ pattern.append("+00"); //$NON-NLS-1$
+ decimalFormat.applyPattern(pattern.toString());
+ String formattedString = decimalFormat.format(argument);
+ result.append(formattedString.replace('E', 'e'));
+
+ // if the flag is sharp and decimal seperator is always given
+ // out.
+ if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
+ && 0 == formatToken.getPrecision()) {
+ int indexOfE = result.indexOf("e"); //$NON-NLS-1$
+ char dot = decimalFormat.getDecimalFormatSymbols()
+ .getDecimalSeparator();
+ result.insert(indexOfE, dot);
+ }
+ }
+
+ void transform_g() {
+ int precision = formatToken.getPrecision();
+ precision = (0 == precision ? 1 : precision);
+ formatToken.setPrecision(precision);
+
+ if (0.0 == ((Number) argument).doubleValue()) {
+ precision--;
+ formatToken.setPrecision(precision);
+ transform_f();
+ return;
+ }
+
+ boolean requireScientificRepresentation = true;
+ double d = ((Number) argument).doubleValue();
+ d = Math.abs(d);
+ long l = Math.round(d);
+
+ if (l >= 1) {
+ if (l < Math.pow(10, precision)) {
+ requireScientificRepresentation = false;
+ precision -= String.valueOf(l).length();
+ precision = precision < 0 ? 0 : precision;
+ l = Math.round(d * Math.pow(10, precision + 1));
+ if (String.valueOf(l).length() <= formatToken
+ .getPrecision()) {
+ precision++;
+ }
+ formatToken.setPrecision(precision);
+ }
+
+ } else {
+ l = Math.round(d * Math.pow(10, 4));
+ if (l >= 1) {
+ requireScientificRepresentation = false;
+ precision += 4 - String.valueOf(l).length();
+ l = Math.round(d * Math.pow(10, precision + 1));
+ if (String.valueOf(l).length() <= formatToken
+ .getPrecision()) {
+ precision++;
+ }
+ l = Math.round(d * Math.pow(10, precision));
+ if (l < Math.pow(10, precision - 4)) {
+ requireScientificRepresentation = true;
+ } else {
+ formatToken.setPrecision(precision);
+ }
+ }
+ }
+ if (requireScientificRepresentation) {
+ precision = formatToken.getPrecision();
+ precision--;
+ formatToken.setPrecision(precision);
+ transform_e();
+ } else {
+ transform_f();
+ }
+
+ }
+
+ void transform_f() {
+ StringBuilder pattern = new StringBuilder();
+ if (formatToken.isFlagSet(FormatToken.FLAG_COMMA)) {
+ pattern.append(',');
+ int groupingSize = decimalFormat.getGroupingSize();
+ if (groupingSize > 1) {
+ char[] sharps = new char[groupingSize - 1];
+ Arrays.fill(sharps, '#');
+ pattern.append(sharps);
+ }
+ }
+
+ pattern.append(0);
+
+ if (formatToken.getPrecision() > 0) {
+ pattern.append('.');
+ char[] zeros = new char[formatToken.getPrecision()];
+ Arrays.fill(zeros, '0');
+ pattern.append(zeros);
+ }
+ decimalFormat.applyPattern(pattern.toString());
+ result.append(decimalFormat.format(argument));
+ // if the flag is sharp and decimal seperator is always given
+ // out.
+ if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)
+ && 0 == formatToken.getPrecision()) {
+ char dot = decimalFormat.getDecimalFormatSymbols()
+ .getDecimalSeparator();
+ result.append(dot);
+ }
+
+ }
+
+ void transform_a() {
+ char currentConversionType = formatToken.getConversionType();
+
+ if (argument instanceof Float) {
+ Float F = (Float) argument;
+ result.append(Float.toHexString(F.floatValue()));
+
+ } else if (argument instanceof Double) {
+ Double D = (Double) argument;
+ result.append(Double.toHexString(D.doubleValue()));
+ } else {
+ // BigInteger is not supported.
+ throw new IllegalFormatConversionException(currentConversionType, argument.getClass());
+ }
+
+ if (!formatToken.isPrecisionSet()) {
+ return;
+ }
+
+ int precision = formatToken.getPrecision();
+ precision = (0 == precision ? 1 : precision);
+ int indexOfFirstFracitoanlDigit = result.indexOf(".") + 1; //$NON-NLS-1$
+ int indexOfP = result.indexOf("p"); //$NON-NLS-1$
+ int fractionalLength = indexOfP - indexOfFirstFracitoanlDigit;
+
+ if (fractionalLength == precision) {
+ return;
+ }
+
+ if (fractionalLength < precision) {
+ char zeros[] = new char[precision - fractionalLength];
+ Arrays.fill(zeros, '0');
+ result.insert(indexOfP, zeros);
+ return;
+ }
+ result
+ .delete(indexOfFirstFracitoanlDigit + precision,
+ indexOfP);
+ }
}
/*
@@ -1435,6 +1773,7 @@
*/
private String transformFromDateTime() {
int startIndex = 0;
+ char currentConversionType = formatToken.getConversionType();
if (formatToken.isPrecisionSet()) {
throw new IllegalFormatPrecisionException(formatToken
@@ -1443,13 +1782,13 @@
if (formatToken.isFlagSet(FormatToken.FLAG_SHARP)) {
throw new FormatFlagsConversionMismatchException(formatToken
- .getStrFlags(), formatToken.getConversionType());
+ .getStrFlags(), currentConversionType);
}
if (formatToken.isFlagSet(FormatToken.FLAG_MINUS)
&& FormatToken.UNSET == formatToken.getWidth()) {
throw new MissingFormatWidthException("-" //$NON-NLS-1$
- + formatToken.getConversionType());
+ + currentConversionType);
}
if (null == arg) {
@@ -1466,8 +1805,7 @@
} else if (arg instanceof Date) {
date = (Date) arg;
} else {
- throw new IllegalFormatConversionException(formatToken
- .getConversionType(), arg.getClass());
+ throw new IllegalFormatConversionException(currentConversionType, arg.getClass());
}
calendar = Calendar.getInstance(locale);
calendar.setTime(date);
@@ -2090,18 +2428,18 @@
/*
* Parses integer value from the given buffer
*/
- private int parseInt(CharBuffer format) {
- int start = format.position() - 1;
- int end = format.limit();
- while (format.hasRemaining()) {
- if (!Character.isDigit(format.get())) {
- end = format.position() - 1;
+ private int parseInt(CharBuffer buffer) {
+ int start = buffer.position() - 1;
+ int end = buffer.limit();
+ while (buffer.hasRemaining()) {
+ if (!Character.isDigit(buffer.get())) {
+ end = buffer.position() - 1;
break;
}
}
- format.position(0);
- String intStr = format.subSequence(start, end).toString();
- format.position(end);
+ buffer.position(0);
+ String intStr = buffer.subSequence(start, end).toString();
+ buffer.position(end);
try {
return Integer.parseInt(intStr);
} catch (NumberFormatException e) {