//
|
//(c) 2000 Sun Microsystems, Inc.
|
//ALL RIGHTS RESERVED
|
//
|
//License Grant-
|
//
|
//
|
//Permission to use, copy, modify, and distribute this Software and its
|
//documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is
|
//hereby granted.
|
//
|
//This Software is provided "AS IS". All express warranties, including any
|
//implied warranty of merchantability, satisfactory quality, fitness for a
|
//particular purpose, or non-infringement, are disclaimed, except to the extent
|
//that such disclaimers are held to be legally invalid.
|
//
|
//You acknowledge that Software is not designed, licensed or intended for use in
|
//the design, construction, operation or maintenance of any nuclear facility
|
//("High Risk Activities"). Sun disclaims any express or implied warranty of
|
//fitness for such uses.
|
//
|
//Please refer to the file http://www.sun.com/policies/trademarks/ for further
|
//important trademark information and to
|
//http://java.sun.com/nav/business/index.html for further important licensing
|
//information for the Java Technology.
|
//
|
|
package com.ximple.util;
|
|
//~--- JDK imports ------------------------------------------------------------
|
|
import java.text.DecimalFormatSymbols;
|
import java.util.Enumeration;
|
import java.util.Locale;
|
import java.util.Vector;
|
|
/**
|
* PrintfFormat allows the formatting of an array of
|
* objects embedded within a string. Primitive types
|
* must be passed using wrapper types. The formatting
|
* is controlled by a control string.
|
* <p>
|
* A control string is a Java string that contains a
|
* control specification. The control specification
|
* starts at the first percent sign (%) in the string,
|
* provided that this percent sign
|
* <ol>
|
* <li>is not escaped protected by a matching % or is
|
* not an escape % character,
|
* <li>is not at the end of the format string, and
|
* <li>precedes a sequence of characters that parses as
|
* a valid control specification.
|
* </ol>
|
* </p><p>
|
* A control specification usually takes the form:
|
* <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
|
* { [hlL] }+ [idfgGoxXeEcs]
|
* </pre>
|
* There are variants of this basic form that are
|
* discussed below.</p>
|
* <p>
|
* The format is composed of zero or more directives
|
* defined as follows:
|
* <ul>
|
* <li>ordinary characters, which are simply copied to
|
* the output stream;
|
* <li>escape sequences, which represent non-graphic
|
* characters; and
|
* <li>conversion specifications, each of which
|
* results in the fetching of zero or more arguments.
|
* </ul></p>
|
* <p>
|
* The results are undefined if there are insufficient
|
* arguments for the format. Usually an unchecked
|
* exception will be thrown. If the format is
|
* exhausted while arguments remain, the excess
|
* arguments are evaluated but are otherwise ignored.
|
* In format strings containing the % form of
|
* conversion specifications, each argument in the
|
* argument list is used exactly once.</p>
|
* <p>
|
* Conversions can be applied to the <code>n</code>th
|
* argument after the format in the argument list,
|
* rather than to the next unused argument. In this
|
* case, the conversion characer % is replaced by the
|
* sequence %<code>n</code>$, where <code>n</code> is
|
* a decimal integer giving the position of the
|
* argument in the argument list.</p>
|
* <p>
|
* In format strings containing the %<code>n</code>$
|
* form of conversion specifications, each argument
|
* in the argument list is used exactly once.</p>
|
*
|
* <h4>Escape Sequences</h4>
|
* <p>
|
* The following table lists escape sequences and
|
* associated actions on display devices capable of
|
* the action.
|
* <table>
|
* <tr><th align=left>Sequence</th>
|
* <th align=left>Name</th>
|
* <th align=left>Description</th></tr>
|
* <tr><td>\\</td><td>backlash</td><td>None.
|
* </td></tr>
|
* <tr><td>\a</td><td>alert</td><td>Attempts to alert
|
* the user through audible or visible
|
* notification.
|
* </td></tr>
|
* <tr><td>\b</td><td>backspace</td><td>Moves the
|
* printing position to one column before
|
* the current position, unless the
|
* current position is the start of a line.
|
* </td></tr>
|
* <tr><td>\f</td><td>form-feed</td><td>Moves the
|
* printing position to the initial
|
* printing position of the next logical
|
* page.
|
* </td></tr>
|
* <tr><td>\n</td><td>newline</td><td>Moves the
|
* printing position to the start of the
|
* next line.
|
* </td></tr>
|
* <tr><td>\r</td><td>carriage-return</td><td>Moves
|
* the printing position to the start of
|
* the current line.
|
* </td></tr>
|
* <tr><td>\t</td><td>tab</td><td>Moves the printing
|
* position to the next implementation-
|
* defined horizontal tab position.
|
* </td></tr>
|
* <tr><td>\v</td><td>vertical-tab</td><td>Moves the
|
* printing position to the start of the
|
* next implementation-defined vertical
|
* tab position.
|
* </td></tr>
|
* </table></p>
|
* <h4>Conversion Specifications</h4>
|
* <p>
|
* Each conversion specification is introduced by
|
* the percent sign character (%). After the character
|
* %, the following appear in sequence:</p>
|
* <p>
|
* Zero or more flags (in any order), which modify the
|
* meaning of the conversion specification.</p>
|
* <p>
|
* An optional minimum field width. If the converted
|
* value has fewer characters than the field width, it
|
* will be padded with spaces by default on the left;
|
* t will be padded on the right, if the left-
|
* adjustment flag (-), described below, is given to
|
* the field width. The field width takes the form
|
* of a decimal integer. If the conversion character
|
* is s, the field width is the the minimum number of
|
* characters to be printed.</p>
|
* <p>
|
* An optional precision that gives the minumum number
|
* of digits to appear for the d, i, o, x or X
|
* conversions (the field is padded with leading
|
* zeros); the number of digits to appear after the
|
* radix character for the e, E, and f conversions,
|
* the maximum number of significant digits for the g
|
* and G conversions; or the maximum number of
|
* characters to be written from a string is s and S
|
* conversions. The precision takes the form of an
|
* optional decimal digit string, where a null digit
|
* string is treated as 0. If a precision appears
|
* with a c conversion character the precision is
|
* ignored.
|
* </p>
|
* <p>
|
* An optional h specifies that a following d, i, o,
|
* x, or X conversion character applies to a type
|
* short argument (the argument will be promoted
|
* according to the integral promotions and its value
|
* converted to type short before printing).</p>
|
* <p>
|
* An optional l (ell) specifies that a following
|
* d, i, o, x, or X conversion character applies to a
|
* type long argument.</p>
|
* <p>
|
* A field width or precision may be indicated by an
|
* asterisk (*) instead of a digit string. In this
|
* case, an integer argument supplised the field width
|
* precision. The argument that is actually converted
|
* is not fetched until the conversion letter is seen,
|
* so the the arguments specifying field width or
|
* precision must appear before the argument (if any)
|
* to be converted. If the precision argument is
|
* negative, it will be changed to zero. A negative
|
* field width argument is taken as a - flag, followed
|
* by a positive field width.</p>
|
* <p>
|
* In format strings containing the %<code>n</code>$
|
* form of a conversion specification, a field width
|
* or precision may be indicated by the sequence
|
* *<code>m</code>$, where m is a decimal integer
|
* giving the position in the argument list (after the
|
* format argument) of an integer argument containing
|
* the field width or precision.</p>
|
* <p>
|
* The format can contain either numbered argument
|
* specifications (that is, %<code>n</code>$ and
|
* *<code>m</code>$), or unnumbered argument
|
* specifications (that is % and *), but normally not
|
* both. The only exception to this is that %% can
|
* be mixed with the %<code>n</code>$ form. The
|
* results of mixing numbered and unnumbered argument
|
* specifications in a format string are undefined.</p>
|
*
|
* <h4>Flag Characters</h4>
|
* <p>
|
* The flags and their meanings are:</p>
|
* <dl>
|
* <dt>'<dd> integer portion of the result of a
|
* decimal conversion (%i, %d, %f, %g, or %G) will
|
* be formatted with thousands' grouping
|
* characters. For other conversions the flag
|
* is ignored. The non-monetary grouping
|
* character is used.
|
* <dt>-<dd> result of the conversion is left-justified
|
* within the field. (It will be right-justified
|
* if this flag is not specified).</td></tr>
|
* <dt>+<dd> result of a signed conversion always
|
* begins with a sign (+ or -). (It will begin
|
* with a sign only when a negative value is
|
* converted if this flag is not specified.)
|
* <dt><space><dd> If the first character of a
|
* signed conversion is not a sign, a space
|
* character will be placed before the result.
|
* This means that if the space character and +
|
* flags both appear, the space flag will be
|
* ignored.
|
* <dt>#<dd> value is to be converted to an alternative
|
* form. For c, d, i, and s conversions, the flag
|
* has no effect. For o conversion, it increases
|
* the precision to force the first digit of the
|
* result to be a zero. For x or X conversion, a
|
* non-zero result has 0x or 0X prefixed to it,
|
* respectively. For e, E, f, g, and G
|
* conversions, the result always contains a radix
|
* character, even if no digits follow the radix
|
* character (normally, a decimal point appears in
|
* the result of these conversions only if a digit
|
* follows it). For g and G conversions, trailing
|
* zeros will not be removed from the result as
|
* they normally are.
|
* <dt>0<dd> d, i, o, x, X, e, E, f, g, and G
|
* conversions, leading zeros (following any
|
* indication of sign or base) are used to pad to
|
* the field width; no space padding is
|
* performed. If the 0 and - flags both appear,
|
* the 0 flag is ignored. For d, i, o, x, and X
|
* conversions, if a precision is specified, the
|
* 0 flag will be ignored. For c conversions,
|
* the flag is ignored.
|
* </dl>
|
*
|
* <h4>Conversion Characters</h4>
|
* <p>
|
* Each conversion character results in fetching zero
|
* or more arguments. The results are undefined if
|
* there are insufficient arguments for the format.
|
* Usually, an unchecked exception will be thrown.
|
* If the format is exhausted while arguments remain,
|
* the excess arguments are ignored.</p>
|
*
|
* <p>
|
* The conversion characters and their meanings are:
|
* </p>
|
* <dl>
|
* <dt>d,i<dd>The int argument is converted to a
|
* signed decimal in the style [-]dddd. The
|
* precision specifies the minimum number of
|
* digits to appear; if the value being
|
* converted can be represented in fewer
|
* digits, it will be expanded with leading
|
* zeros. The default precision is 1. The
|
* result of converting 0 with an explicit
|
* precision of 0 is no characters.
|
* <dt>o<dd> The int argument is converted to unsigned
|
* octal format in the style ddddd. The
|
* precision specifies the minimum number of
|
* digits to appear; if the value being
|
* converted can be represented in fewer
|
* digits, it will be expanded with leading
|
* zeros. The default precision is 1. The
|
* result of converting 0 with an explicit
|
* precision of 0 is no characters.
|
* <dt>x<dd> The int argument is converted to unsigned
|
* hexadecimal format in the style dddd; the
|
* letters abcdef are used. The precision
|
* specifies the minimum numberof digits to
|
* appear; if the value being converted can be
|
* represented in fewer digits, it will be
|
* expanded with leading zeros. The default
|
* precision is 1. The result of converting 0
|
* with an explicit precision of 0 is no
|
* characters.
|
* <dt>X<dd> Behaves the same as the x conversion
|
* character except that letters ABCDEF are
|
* used instead of abcdef.
|
* <dt>f<dd> The floating point number argument is
|
* written in decimal notation in the style
|
* [-]ddd.ddd, where the number of digits after
|
* the radix character (shown here as a decimal
|
* point) is equal to the precision
|
* specification. A Locale is used to determine
|
* the radix character to use in this format.
|
* If the precision is omitted from the
|
* argument, six digits are written after the
|
* radix character; if the precision is
|
* explicitly 0 and the # flag is not specified,
|
* no radix character appears. If a radix
|
* character appears, at least 1 digit appears
|
* before it. The value is rounded to the
|
* appropriate number of digits.
|
* <dt>e,E<dd>The floating point number argument is
|
* written in the style [-]d.ddde{+-}dd
|
* (the symbols {+-} indicate either a plus or
|
* minus sign), where there is one digit before
|
* the radix character (shown here as a decimal
|
* point) and the number of digits after it is
|
* equal to the precision. A Locale is used to
|
* determine the radix character to use in this
|
* format. When the precision is missing, six
|
* digits are written after the radix character;
|
* if the precision is 0 and the # flag is not
|
* specified, no radix character appears. The
|
* E conversion will produce a number with E
|
* instead of e introducing the exponent. The
|
* exponent always contains at least two digits.
|
* However, if the value to be written requires
|
* an exponent greater than two digits,
|
* additional exponent digits are written as
|
* necessary. The value is rounded to the
|
* appropriate number of digits.
|
* <dt>g,G<dd>The floating point number argument is
|
* written in style f or e (or in sytle E in the
|
* case of a G conversion character), with the
|
* precision specifying the number of
|
* significant digits. If the precision is
|
* zero, it is taken as one. The style used
|
* depends on the value converted: style e
|
* (or E) will be used only if the exponent
|
* resulting from the conversion is less than
|
* -4 or greater than or equal to the precision.
|
* Trailing zeros are removed from the result.
|
* A radix character appears only if it is
|
* followed by a digit.
|
* <dt>c,C<dd>The integer argument is converted to a
|
* char and the result is written.
|
*
|
* <dt>s,S<dd>The argument is taken to be a string and
|
* bytes from the string are written until the
|
* end of the string or the number of bytes
|
* indicated by the precision specification of
|
* the argument is reached. If the precision
|
* is omitted from the argument, it is taken to
|
* be infinite, so all characters up to the end
|
* of the string are written.
|
* <dt>%<dd>Write a % character; no argument is
|
* converted.
|
* </dl>
|
* <p>
|
* If a conversion specification does not match one of
|
* the above forms, an IllegalArgumentException is
|
* thrown and the instance of PrintfFormat is not
|
* created.</p>
|
* <p>
|
* If a floating point value is the internal
|
* representation for infinity, the output is
|
* [+]Infinity, where Infinity is either Infinity or
|
* Inf, depending on the desired output string length.
|
* Printing of the sign follows the rules described
|
* above.</p>
|
* <p>
|
* If a floating point value is the internal
|
* representation for "not-a-number," the output is
|
* [+]NaN. Printing of the sign follows the rules
|
* described above.</p>
|
* <p>
|
* In no case does a non-existent or small field width
|
* cause truncation of a field; if the result of a
|
* conversion is wider than the field width, the field
|
* is simply expanded to contain the conversion result.
|
* </p>
|
* <p>
|
* The behavior is like printf. One exception is that
|
* the minimum number of exponent digits is 3 instead
|
* of 2 for e and E formats when the optional L is used
|
* before the e, E, g, or G conversion character. The
|
* optional L does not imply conversion to a long long
|
* double. </p>
|
* <p>
|
* The biggest divergence from the C printf
|
* specification is in the use of 16 bit characters.
|
* This allows the handling of characters beyond the
|
* small ASCII character set and allows the utility to
|
* interoperate correctly with the rest of the Java
|
* runtime environment.</p>
|
* <p>
|
* Omissions from the C printf specification are
|
* numerous. All the known omissions are present
|
* because Java never uses bytes to represent
|
* characters and does not have pointers:</p>
|
* <ul>
|
* <li>%c is the same as %C.
|
* <li>%s is the same as %S.
|
* <li>u, p, and n conversion characters.
|
* <li>%ws format.
|
* <li>h modifier applied to an n conversion character.
|
* <li>l (ell) modifier applied to the c, n, or s
|
* conversion characters.
|
* <li>ll (ell ell) modifier to d, i, o, u, x, or X
|
* conversion characters.
|
* <li>ll (ell ell) modifier to an n conversion
|
* character.
|
* <li>c, C, d,i,o,u,x, and X conversion characters
|
* apply to Byte, Character, Short, Integer, Long
|
* types.
|
* <li>f, e, E, g, and G conversion characters apply
|
* to Float and Double types.
|
* <li>s and S conversion characters apply to String
|
* types.
|
* <li>All other reference types can be formatted
|
* using the s or S conversion characters only.
|
* </ul>
|
* <p>
|
* Most of this specification is quoted from the Unix
|
* man page for the sprintf utility.</p>
|
*
|
* @author Allan Jacobs
|
* @version 1
|
* Release 1: Initial release.
|
* Release 2: Asterisk field widths and precisions
|
* %n$ and *m$
|
* Bug fixes
|
* g format fix (2 digits in e form corrupt)
|
* rounding in f format implemented
|
* round up when digit not printed is 5
|
* formatting of -0.0f
|
* round up/down when last digits are 50000...
|
*/
|
public final class PrintfFormat
|
{
|
/** Vector of control strings and format literals. */
|
private Vector vFmt = new Vector();
|
|
/** Character position. Used by the constructor. */
|
private int cPos = 0;
|
|
/** Character position. Used by the constructor. */
|
private DecimalFormatSymbols dfs = null;
|
|
/**
|
* Constructs an array of control specifications
|
* possibly preceded, separated, or followed by
|
* ordinary strings. Control strings begin with
|
* unpaired percent signs. A pair of successive
|
* percent signs designates a single percent sign in
|
* the format.
|
* @param fmtArg Control string.
|
* @exception IllegalArgumentException if the control
|
* string is null, zero length, or otherwise
|
* malformed.
|
*/
|
public PrintfFormat(String fmtArg) throws IllegalArgumentException
|
{
|
this(Locale.getDefault(), fmtArg);
|
}
|
|
/**
|
* Constructs an array of control specifications
|
* possibly preceded, separated, or followed by
|
* ordinary strings. Control strings begin with
|
* unpaired percent signs. A pair of successive
|
* percent signs designates a single percent sign in
|
* the format.
|
* @param fmtArg Control string.
|
* @exception IllegalArgumentException if the control
|
* string is null, zero length, or otherwise
|
* malformed.
|
*/
|
public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException
|
{
|
dfs = new DecimalFormatSymbols(locale);
|
|
int ePos = 0;
|
ConversionSpecification sFmt = null;
|
String unCS = this.nonControl(fmtArg, 0);
|
|
if (unCS != null)
|
{
|
sFmt = new ConversionSpecification();
|
sFmt.setLiteral(unCS);
|
vFmt.addElement(sFmt);
|
}
|
|
while ((cPos != -1) && (cPos < fmtArg.length()))
|
{
|
for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++)
|
{
|
char c = 0;
|
|
c = fmtArg.charAt(ePos);
|
|
if (c == 'i')
|
{
|
break;
|
}
|
|
if (c == 'd')
|
{
|
break;
|
}
|
|
if (c == 'f')
|
{
|
break;
|
}
|
|
if (c == 'g')
|
{
|
break;
|
}
|
|
if (c == 'G')
|
{
|
break;
|
}
|
|
if (c == 'o')
|
{
|
break;
|
}
|
|
if (c == 'x')
|
{
|
break;
|
}
|
|
if (c == 'X')
|
{
|
break;
|
}
|
|
if (c == 'e')
|
{
|
break;
|
}
|
|
if (c == 'E')
|
{
|
break;
|
}
|
|
if (c == 'c')
|
{
|
break;
|
}
|
|
if (c == 's')
|
{
|
break;
|
}
|
|
if (c == '%')
|
{
|
break;
|
}
|
}
|
|
ePos = Math.min(ePos + 1, fmtArg.length());
|
sFmt = new ConversionSpecification(fmtArg.substring(cPos, ePos));
|
vFmt.addElement(sFmt);
|
unCS = this.nonControl(fmtArg, ePos);
|
|
if (unCS != null)
|
{
|
sFmt = new ConversionSpecification();
|
sFmt.setLiteral(unCS);
|
vFmt.addElement(sFmt);
|
}
|
}
|
}
|
|
/**
|
* Return a substring starting at
|
* <code>start</code> and ending at either the end
|
* of the String <code>s</code>, the next unpaired
|
* percent sign, or at the end of the String if the
|
* last character is a percent sign.
|
* @param s Control string.
|
* @param start Position in the string
|
* <code>s</code> to begin looking for the start
|
* of a control string.
|
* @return the substring from the start position
|
* to the beginning of the control string.
|
*/
|
private String nonControl(String s, int start)
|
{
|
String ret = "";
|
|
cPos = s.indexOf("%", start);
|
|
if (cPos == -1)
|
{
|
cPos = s.length();
|
}
|
|
return s.substring(start, cPos);
|
}
|
|
/**
|
* Format an array of objects. Byte, Short,
|
* Integer, Long, Float, Double, and Character
|
* arguments are treated as wrappers for primitive
|
* types.
|
* @param o The array of objects to format.
|
* @return The formatted String.
|
*/
|
public String sprintf(Object[] o)
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
int i = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
} else
|
{
|
if (cs.isPositionalSpecification())
|
{
|
i = cs.getArgumentPosition() - 1;
|
|
if (cs.isPositionalFieldWidth())
|
{
|
int ifw = cs.getArgumentPositionForFieldWidth() - 1;
|
|
cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue());
|
}
|
|
if (cs.isPositionalPrecision())
|
{
|
int ipr = cs.getArgumentPositionForPrecision() - 1;
|
|
cs.setPrecisionWithArg(((Integer) o[ipr]).intValue());
|
}
|
} else
|
{
|
if (cs.isVariableFieldWidth())
|
{
|
cs.setFieldWidthWithArg(((Integer) o[i]).intValue());
|
i++;
|
}
|
|
if (cs.isVariablePrecision())
|
{
|
cs.setPrecisionWithArg(((Integer) o[i]).intValue());
|
i++;
|
}
|
}
|
|
if (o[i] instanceof Byte)
|
{
|
sb.append(cs.internalsprintf(((Byte) o[i]).byteValue()));
|
} else if (o[i] instanceof Short)
|
{
|
sb.append(cs.internalsprintf(((Short) o[i]).shortValue()));
|
} else if (o[i] instanceof Integer)
|
{
|
sb.append(cs.internalsprintf(((Integer) o[i]).intValue()));
|
} else if (o[i] instanceof Long)
|
{
|
sb.append(cs.internalsprintf(((Long) o[i]).longValue()));
|
} else if (o[i] instanceof Float)
|
{
|
sb.append(cs.internalsprintf(((Float) o[i]).floatValue()));
|
} else if (o[i] instanceof Double)
|
{
|
sb.append(cs.internalsprintf(((Double) o[i]).doubleValue()));
|
} else if (o[i] instanceof Character)
|
{
|
sb.append(cs.internalsprintf(((Character) o[i]).charValue()));
|
} else if (o[i] instanceof String)
|
{
|
sb.append(cs.internalsprintf((String) o[i]));
|
} else
|
{
|
sb.append(cs.internalsprintf(o[i]));
|
}
|
|
if (!cs.isPositionalSpecification())
|
{
|
i++;
|
}
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Format nothing. Just use the control string.
|
* @return the formatted String.
|
*/
|
public String sprintf()
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Format an int.
|
* @param x The int to format.
|
* @return The formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is f, e, E, g, G, s,
|
* or S.
|
*/
|
public String sprintf(int x) throws IllegalArgumentException
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
} else
|
{
|
sb.append(cs.internalsprintf(x));
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Format an long.
|
* @param x The long to format.
|
* @return The formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is f, e, E, g, G, s,
|
* or S.
|
*/
|
public String sprintf(long x) throws IllegalArgumentException
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
} else
|
{
|
sb.append(cs.internalsprintf(x));
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Format a double.
|
* @param x The double to format.
|
* @return The formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is c, C, s, S,
|
* d, d, x, X, or o.
|
*/
|
public String sprintf(double x) throws IllegalArgumentException
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
} else
|
{
|
sb.append(cs.internalsprintf(x));
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Format a String.
|
* @param x The String to format.
|
* @return The formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is neither s nor S.
|
*/
|
public String sprintf(String x) throws IllegalArgumentException
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
} else
|
{
|
sb.append(cs.internalsprintf(x));
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* Format an Object. Convert wrapper types to
|
* their primitive equivalents and call the
|
* appropriate internal formatting method. Convert
|
* Strings using an internal formatting method for
|
* Strings. Otherwise use the default formatter
|
* (use toString).
|
* @param x the Object to format.
|
* @return the formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is inappropriate for
|
* formatting an unwrapped value.
|
*/
|
public String sprintf(Object x) throws IllegalArgumentException
|
{
|
Enumeration e = vFmt.elements();
|
ConversionSpecification cs = null;
|
char c = 0;
|
StringBuffer sb = new StringBuffer();
|
|
while (e.hasMoreElements())
|
{
|
cs = (ConversionSpecification) e.nextElement();
|
c = cs.getConversionCharacter();
|
|
if (c == '\0')
|
{
|
sb.append(cs.getLiteral());
|
} else if (c == '%')
|
{
|
sb.append("%");
|
} else
|
{
|
if (x instanceof Byte)
|
{
|
sb.append(cs.internalsprintf(((Byte) x).byteValue()));
|
} else if (x instanceof Short)
|
{
|
sb.append(cs.internalsprintf(((Short) x).shortValue()));
|
} else if (x instanceof Integer)
|
{
|
sb.append(cs.internalsprintf(((Integer) x).intValue()));
|
} else if (x instanceof Long)
|
{
|
sb.append(cs.internalsprintf(((Long) x).longValue()));
|
} else if (x instanceof Float)
|
{
|
sb.append(cs.internalsprintf(((Float) x).floatValue()));
|
} else if (x instanceof Double)
|
{
|
sb.append(cs.internalsprintf(((Double) x).doubleValue()));
|
} else if (x instanceof Character)
|
{
|
sb.append(cs.internalsprintf(((Character) x).charValue()));
|
} else if (x instanceof String)
|
{
|
sb.append(cs.internalsprintf((String) x));
|
} else
|
{
|
sb.append(cs.internalsprintf(x));
|
}
|
}
|
}
|
|
return sb.toString();
|
}
|
|
/**
|
* <p>
|
* ConversionSpecification allows the formatting of
|
* a single primitive or object embedded within a
|
* string. The formatting is controlled by a
|
* format string. Only one Java primitive or
|
* object can be formatted at a time.
|
* <p>
|
* A format string is a Java string that contains
|
* a control string. The control string starts at
|
* the first percent sign (%) in the string,
|
* provided that this percent sign
|
* <ol>
|
* <li>is not escaped protected by a matching % or
|
* is not an escape % character,
|
* <li>is not at the end of the format string, and
|
* <li>precedes a sequence of characters that parses
|
* as a valid control string.
|
* </ol>
|
* <p>
|
* A control string takes the form:
|
* <pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
|
* { [hlL] }+ [idfgGoxXeEcs]
|
* </pre>
|
* <p>
|
* The behavior is like printf. One (hopefully the
|
* only) exception is that the minimum number of
|
* exponent digits is 3 instead of 2 for e and E
|
* formats when the optional L is used before the
|
* e, E, g, or G conversion character. The
|
* optional L does not imply conversion to a long
|
* long double.
|
*/
|
private class ConversionSpecification
|
{
|
/** Default precision. */
|
private final static int defaultDigits = 6;
|
|
/**
|
* The integer portion of the result of a decimal
|
* conversion (i, d, u, f, g, or G) will be
|
* formatted with thousands' grouping characters.
|
* For other conversions the flag is ignored.
|
*/
|
private boolean thousands = false;
|
|
/**
|
* The result of the conversion will be
|
* left-justified within the field.
|
*/
|
private boolean leftJustify = false;
|
|
/**
|
* The result of a signed conversion will always
|
* begin with a sign (+ or -).
|
*/
|
private boolean leadingSign = false;
|
|
/**
|
* Flag indicating that left padding with spaces is
|
* specified.
|
*/
|
private boolean leadingSpace = false;
|
|
/**
|
* For an o conversion, increase the precision to
|
* force the first digit of the result to be a
|
* zero. For x (or X) conversions, a non-zero
|
* result will have 0x (or 0X) prepended to it.
|
* For e, E, f, g, or G conversions, the result
|
* will always contain a radix character, even if
|
* no digits follow the point. For g and G
|
* conversions, trailing zeros will not be removed
|
* from the result.
|
*/
|
private boolean alternateForm = false;
|
|
/**
|
* Flag indicating that left padding with zeroes is
|
* specified.
|
*/
|
private boolean leadingZeros = false;
|
|
/**
|
* Flag indicating that the field width is *.
|
*/
|
private boolean variableFieldWidth = false;
|
|
/**
|
* If the converted value has fewer bytes than the
|
* field width, it will be padded with spaces or
|
* zeroes.
|
*/
|
private int fieldWidth = 0;
|
|
/**
|
* Flag indicating whether or not the field width
|
* has been set.
|
*/
|
private boolean fieldWidthSet = false;
|
|
/**
|
* The minimum number of digits to appear for the
|
* d, i, o, u, x, or X conversions. The number of
|
* digits to appear after the radix character for
|
* the e, E, and f conversions. The maximum number
|
* of significant digits for the g and G
|
* conversions. The maximum number of bytes to be
|
* printed from a string in s and S conversions.
|
*/
|
private int precision = 0;
|
|
/**
|
* Flag indicating that the precision is *.
|
*/
|
private boolean variablePrecision = false;
|
|
/**
|
* Flag indicating whether or not the precision has
|
* been set.
|
*/
|
private boolean precisionSet = false;
|
|
/*
|
*/
|
private boolean positionalSpecification = false;
|
private int argumentPosition = 0;
|
private boolean positionalFieldWidth = false;
|
private int argumentPositionForFieldWidth = 0;
|
private boolean positionalPrecision = false;
|
private int argumentPositionForPrecision = 0;
|
|
/**
|
* Flag specifying that a following d, i, o, u, x,
|
* or X conversion character applies to a type
|
* short int.
|
*/
|
private boolean optionalh = false;
|
|
/**
|
* Flag specifying that a following d, i, o, u, x,
|
* or X conversion character applies to a type lont
|
* int argument.
|
*/
|
private boolean optionall = false;
|
|
/**
|
* Flag specifying that a following e, E, f, g, or
|
* G conversion character applies to a type double
|
* argument. This is a noop in Java.
|
*/
|
private boolean optionalL = false;
|
|
/** Control string type. */
|
private char conversionCharacter = '\0';
|
|
/**
|
* Position within the control string. Used by
|
* the constructor.
|
*/
|
private int pos = 0;
|
|
/** Literal or control format string. */
|
private String fmt;
|
|
/**
|
* Constructor. Used to prepare an instance
|
* to hold a literal, not a control string.
|
*/
|
ConversionSpecification()
|
{
|
}
|
|
/**
|
* Constructor for a conversion specification.
|
* The argument must begin with a % and end
|
* with the conversion character for the
|
* conversion specification.
|
* @param fmtArg String specifying the
|
* conversion specification.
|
* @exception IllegalArgumentException if the
|
* input string is null, zero length, or
|
* otherwise malformed.
|
*/
|
ConversionSpecification(String fmtArg) throws IllegalArgumentException
|
{
|
if (fmtArg == null)
|
{
|
throw new NullPointerException();
|
}
|
|
if (fmtArg.length() == 0)
|
{
|
throw new IllegalArgumentException("Control strings must have positive" + " lengths.");
|
}
|
|
if (fmtArg.charAt(0) == '%')
|
{
|
fmt = fmtArg;
|
pos = 1;
|
setArgPosition();
|
setFlagCharacters();
|
setFieldWidth();
|
setPrecision();
|
setOptionalHL();
|
|
if (setConversionCharacter())
|
{
|
if (pos == fmtArg.length())
|
{
|
if (leadingZeros && leftJustify)
|
{
|
leadingZeros = false;
|
}
|
|
if (precisionSet && leadingZeros)
|
{
|
if ((conversionCharacter == 'd') || (conversionCharacter == 'i') || (conversionCharacter == 'o')
|
|| (conversionCharacter == 'x'))
|
{
|
leadingZeros = false;
|
}
|
}
|
} else
|
{
|
throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
|
}
|
} else
|
{
|
throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
|
}
|
} else
|
{
|
throw new IllegalArgumentException("Control strings must begin with %.");
|
}
|
}
|
|
/**
|
* Set the String for this instance.
|
* @param s the String to store.
|
*/
|
void setLiteral(String s)
|
{
|
fmt = s;
|
}
|
|
/**
|
* Get the String for this instance. Translate
|
* any escape sequences.
|
*
|
* @return s the stored String.
|
*/
|
String getLiteral()
|
{
|
StringBuffer sb = new StringBuffer();
|
int i = 0;
|
|
while (i < fmt.length())
|
{
|
if (fmt.charAt(i) == '\\')
|
{
|
i++;
|
|
if (i < fmt.length())
|
{
|
char c = fmt.charAt(i);
|
|
switch (c)
|
{
|
case 'a' :
|
sb.append((char) 0x07);
|
|
break;
|
|
case 'b' :
|
sb.append('\b');
|
|
break;
|
|
case 'f' :
|
sb.append('\f');
|
|
break;
|
|
case 'n' :
|
sb.append(System.getProperty("line.separator"));
|
|
break;
|
|
case 'r' :
|
sb.append('\r');
|
|
break;
|
|
case 't' :
|
sb.append('\t');
|
|
break;
|
|
case 'v' :
|
sb.append((char) 0x0b);
|
|
break;
|
|
case '\\' :
|
sb.append('\\');
|
|
break;
|
}
|
|
i++;
|
} else
|
{
|
sb.append('\\');
|
}
|
} else
|
{
|
i++;
|
}
|
}
|
|
return fmt;
|
}
|
|
/**
|
* Get the conversion character that tells what
|
* type of control character this instance has.
|
*
|
* @return the conversion character.
|
*/
|
char getConversionCharacter()
|
{
|
return conversionCharacter;
|
}
|
|
/**
|
* Check whether the specifier has a variable
|
* field width that is going to be set by an
|
* argument.
|
* @return <code>true</code> if the conversion
|
* uses an * field width; otherwise
|
* <code>false</code>.
|
*/
|
boolean isVariableFieldWidth()
|
{
|
return variableFieldWidth;
|
}
|
|
/**
|
* Set the field width with an argument. A
|
* negative field width is taken as a - flag
|
* followed by a positive field width.
|
* @param fw the field width.
|
*/
|
void setFieldWidthWithArg(int fw)
|
{
|
if (fw < 0)
|
{
|
leftJustify = true;
|
}
|
|
fieldWidthSet = true;
|
fieldWidth = Math.abs(fw);
|
}
|
|
/**
|
* Check whether the specifier has a variable
|
* precision that is going to be set by an
|
* argument.
|
* @return <code>true</code> if the conversion
|
* uses an * precision; otherwise
|
* <code>false</code>.
|
*/
|
boolean isVariablePrecision()
|
{
|
return variablePrecision;
|
}
|
|
/**
|
* Set the precision with an argument. A
|
* negative precision will be changed to zero.
|
* @param pr the precision.
|
*/
|
void setPrecisionWithArg(int pr)
|
{
|
precisionSet = true;
|
precision = Math.max(pr, 0);
|
}
|
|
/**
|
* Format an int argument using this conversion
|
* specification.
|
* @param s the int to format.
|
* @return the formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is f, e, E, g, or G.
|
*/
|
String internalsprintf(int s) throws IllegalArgumentException
|
{
|
String s2 = "";
|
|
switch (conversionCharacter)
|
{
|
case 'd' :
|
case 'i' :
|
if (optionalh)
|
{
|
s2 = printDFormat((short) s);
|
} else if (optionall)
|
{
|
s2 = printDFormat((long) s);
|
} else
|
{
|
s2 = printDFormat(s);
|
}
|
|
break;
|
|
case 'x' :
|
case 'X' :
|
if (optionalh)
|
{
|
s2 = printXFormat((short) s);
|
} else if (optionall)
|
{
|
s2 = printXFormat((long) s);
|
} else
|
{
|
s2 = printXFormat(s);
|
}
|
|
break;
|
|
case 'o' :
|
if (optionalh)
|
{
|
s2 = printOFormat((short) s);
|
} else if (optionall)
|
{
|
s2 = printOFormat((long) s);
|
} else
|
{
|
s2 = printOFormat(s);
|
}
|
|
break;
|
|
case 'c' :
|
case 'C' :
|
s2 = printCFormat((char) s);
|
|
break;
|
|
default :
|
throw new IllegalArgumentException("Cannot format a int with a format using a " + conversionCharacter
|
+ " conversion character.");
|
}
|
|
return s2;
|
}
|
|
/**
|
* Format a long argument using this conversion
|
* specification.
|
* @param s the long to format.
|
* @return the formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is f, e, E, g, or G.
|
*/
|
String internalsprintf(long s) throws IllegalArgumentException
|
{
|
String s2 = "";
|
|
switch (conversionCharacter)
|
{
|
case 'd' :
|
case 'i' :
|
if (optionalh)
|
{
|
s2 = printDFormat((short) s);
|
} else if (optionall)
|
{
|
s2 = printDFormat(s);
|
} else
|
{
|
s2 = printDFormat((int) s);
|
}
|
|
break;
|
|
case 'x' :
|
case 'X' :
|
if (optionalh)
|
{
|
s2 = printXFormat((short) s);
|
} else if (optionall)
|
{
|
s2 = printXFormat(s);
|
} else
|
{
|
s2 = printXFormat((int) s);
|
}
|
|
break;
|
|
case 'o' :
|
if (optionalh)
|
{
|
s2 = printOFormat((short) s);
|
} else if (optionall)
|
{
|
s2 = printOFormat(s);
|
} else
|
{
|
s2 = printOFormat((int) s);
|
}
|
|
break;
|
|
case 'c' :
|
case 'C' :
|
s2 = printCFormat((char) s);
|
|
break;
|
|
default :
|
throw new IllegalArgumentException("Cannot format a long with a format using a " + conversionCharacter
|
+ " conversion character.");
|
}
|
|
return s2;
|
}
|
|
/**
|
* Format a double argument using this conversion
|
* specification.
|
* @param s the double to format.
|
* @return the formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is c, C, s, S, i, d,
|
* x, X, or o.
|
*/
|
String internalsprintf(double s) throws IllegalArgumentException
|
{
|
String s2 = "";
|
|
switch (conversionCharacter)
|
{
|
case 'f' :
|
s2 = printFFormat(s);
|
|
break;
|
|
case 'E' :
|
case 'e' :
|
s2 = printEFormat(s);
|
|
break;
|
|
case 'G' :
|
case 'g' :
|
s2 = printGFormat(s);
|
|
break;
|
|
default :
|
throw new IllegalArgumentException("Cannot " + "format a double with a format using a " + conversionCharacter
|
+ " conversion character.");
|
}
|
|
return s2;
|
}
|
|
/**
|
* Format a String argument using this conversion
|
* specification.
|
* @param s the String to format.
|
* @return the formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is neither s nor S.
|
*/
|
String internalsprintf(String s) throws IllegalArgumentException
|
{
|
String s2 = "";
|
|
if ((conversionCharacter == 's') || (conversionCharacter == 'S'))
|
{
|
s2 = printSFormat(s);
|
} else
|
{
|
throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + conversionCharacter
|
+ " conversion character.");
|
}
|
|
return s2;
|
}
|
|
/**
|
* Format an Object argument using this conversion
|
* specification.
|
* @param s the Object to format.
|
* @return the formatted String.
|
* @exception IllegalArgumentException if the
|
* conversion character is neither s nor S.
|
*/
|
String internalsprintf(Object s)
|
{
|
String s2 = "";
|
|
if ((conversionCharacter == 's') || (conversionCharacter == 'S'))
|
{
|
s2 = printSFormat(s.toString());
|
} else
|
{
|
throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + conversionCharacter
|
+ " conversion character.");
|
}
|
|
return s2;
|
}
|
|
/**
|
* For f format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. '+' character means that the conversion
|
* will always begin with a sign (+ or -). The
|
* blank flag character means that a non-negative
|
* input will be preceded with a blank. If both
|
* a '+' and a ' ' are specified, the blank flag
|
* is ignored. The '0' flag character implies that
|
* padding to the field width will be done with
|
* zeros instead of blanks.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the number of digits
|
* to appear after the radix character. Padding is
|
* with trailing 0s.
|
*/
|
private char[] fFormatDigits(double x)
|
{
|
// int defaultDigits=6;
|
String sx, sxOut;
|
int i, j, k;
|
int n1In, n2In;
|
int expon = 0;
|
boolean minusSign = false;
|
|
if (x > 0.0)
|
{
|
sx = Double.toString(x);
|
} else if (x < 0.0)
|
{
|
sx = Double.toString(-x);
|
minusSign = true;
|
} else
|
{
|
sx = Double.toString(x);
|
|
if (sx.charAt(0) == '-')
|
{
|
minusSign = true;
|
sx = sx.substring(1);
|
}
|
}
|
|
int ePos = sx.indexOf('E');
|
int rPos = sx.indexOf('.');
|
|
if (rPos != -1)
|
{
|
n1In = rPos;
|
} else if (ePos != -1)
|
{
|
n1In = ePos;
|
} else
|
{
|
n1In = sx.length();
|
}
|
|
if (rPos != -1)
|
{
|
if (ePos != -1)
|
{
|
n2In = ePos - rPos - 1;
|
} else
|
{
|
n2In = sx.length() - rPos - 1;
|
}
|
} else
|
{
|
n2In = 0;
|
}
|
|
if (ePos != -1)
|
{
|
int ie = ePos + 1;
|
|
expon = 0;
|
|
if (sx.charAt(ie) == '-')
|
{
|
for (++ie; ie < sx.length(); ie++)
|
{
|
if (sx.charAt(ie) != '0')
|
{
|
break;
|
}
|
}
|
|
if (ie < sx.length())
|
{
|
expon = -Integer.parseInt(sx.substring(ie));
|
}
|
} else
|
{
|
if (sx.charAt(ie) == '+')
|
{
|
++ie;
|
}
|
|
for (; ie < sx.length(); ie++)
|
{
|
if (sx.charAt(ie) != '0')
|
{
|
break;
|
}
|
}
|
|
if (ie < sx.length())
|
{
|
expon = Integer.parseInt(sx.substring(ie));
|
}
|
}
|
}
|
|
int p;
|
|
if (precisionSet)
|
{
|
p = precision;
|
} else
|
{
|
p = defaultDigits - 1;
|
}
|
|
char[] ca1 = sx.toCharArray();
|
char[] ca2 = new char[n1In + n2In];
|
char[] ca3, ca4, ca5;
|
|
for (j = 0; j < n1In; j++)
|
{
|
ca2[j] = ca1[j];
|
}
|
|
i = j + 1;
|
|
for (k = 0; k < n2In; j++, i++, k++)
|
{
|
ca2[j] = ca1[i];
|
}
|
|
if (n1In + expon <= 0)
|
{
|
ca3 = new char[-expon + n2In];
|
|
for (j = 0, k = 0; k < (-n1In - expon); k++, j++)
|
{
|
ca3[j] = '0';
|
}
|
|
for (i = 0; i < (n1In + n2In); i++, j++)
|
{
|
ca3[j] = ca2[i];
|
}
|
} else
|
{
|
ca3 = ca2;
|
}
|
|
boolean carry = false;
|
|
if (p < -expon + n2In)
|
{
|
if (expon < 0)
|
{
|
i = p;
|
} else
|
{
|
i = p + n1In;
|
}
|
|
carry = checkForCarry(ca3, i);
|
|
if (carry)
|
{
|
carry = startSymbolicCarry(ca3, i - 1, 0);
|
}
|
}
|
|
if (n1In + expon <= 0)
|
{
|
ca4 = new char[2 + p];
|
|
if (!carry)
|
{
|
ca4[0] = '0';
|
} else
|
{
|
ca4[0] = '1';
|
}
|
|
if (alternateForm ||!precisionSet || (precision != 0))
|
{
|
ca4[1] = '.';
|
|
for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
|
{
|
ca4[j] = ca3[i];
|
}
|
|
for (; j < ca4.length; j++)
|
{
|
ca4[j] = '0';
|
}
|
}
|
} else
|
{
|
if (!carry)
|
{
|
if (alternateForm ||!precisionSet || (precision != 0))
|
{
|
ca4 = new char[n1In + expon + p + 1];
|
} else
|
{
|
ca4 = new char[n1In + expon];
|
}
|
|
j = 0;
|
} else
|
{
|
if (alternateForm ||!precisionSet || (precision != 0))
|
{
|
ca4 = new char[n1In + expon + p + 2];
|
} else
|
{
|
ca4 = new char[n1In + expon + 1];
|
}
|
|
ca4[0] = '1';
|
j = 1;
|
}
|
|
for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
|
{
|
ca4[j] = ca3[i];
|
}
|
|
for (; i < n1In + expon; i++, j++)
|
{
|
ca4[j] = '0';
|
}
|
|
if (alternateForm ||!precisionSet || (precision != 0))
|
{
|
ca4[j] = '.';
|
j++;
|
|
for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++)
|
{
|
ca4[j] = ca3[i];
|
}
|
|
for (; j < ca4.length; j++)
|
{
|
ca4[j] = '0';
|
}
|
}
|
}
|
|
int nZeros = 0;
|
|
if (!leftJustify && leadingZeros)
|
{
|
int xThousands = 0;
|
|
if (thousands)
|
{
|
int xlead = 0;
|
|
if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' '))
|
{
|
xlead = 1;
|
}
|
|
int xdp = xlead;
|
|
for (; xdp < ca4.length; xdp++)
|
{
|
if (ca4[xdp] == '.')
|
{
|
break;
|
}
|
}
|
|
xThousands = (xdp - xlead) / 3;
|
}
|
|
if (fieldWidthSet)
|
{
|
nZeros = fieldWidth - ca4.length;
|
}
|
|
if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
|
{
|
nZeros--;
|
}
|
|
nZeros -= xThousands;
|
|
if (nZeros < 0)
|
{
|
nZeros = 0;
|
}
|
}
|
|
j = 0;
|
|
if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
|
{
|
ca5 = new char[ca4.length + nZeros + 1];
|
j++;
|
} else
|
{
|
ca5 = new char[ca4.length + nZeros];
|
}
|
|
if (!minusSign)
|
{
|
if (leadingSign)
|
{
|
ca5[0] = '+';
|
}
|
|
if (leadingSpace)
|
{
|
ca5[0] = ' ';
|
}
|
} else
|
{
|
ca5[0] = '-';
|
}
|
|
for (i = 0; i < nZeros; i++, j++)
|
{
|
ca5[j] = '0';
|
}
|
|
for (i = 0; i < ca4.length; i++, j++)
|
{
|
ca5[j] = ca4[i];
|
}
|
|
int lead = 0;
|
|
if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' '))
|
{
|
lead = 1;
|
}
|
|
int dp = lead;
|
|
for (; dp < ca5.length; dp++)
|
{
|
if (ca5[dp] == '.')
|
{
|
break;
|
}
|
}
|
|
int nThousands = (dp - lead) / 3;
|
|
// Localize the decimal point.
|
if (dp < ca5.length)
|
{
|
ca5[dp] = dfs.getDecimalSeparator();
|
}
|
|
char[] ca6 = ca5;
|
|
if (thousands && (nThousands > 0))
|
{
|
ca6 = new char[ca5.length + nThousands + lead];
|
ca6[0] = ca5[0];
|
|
for (i = lead, k = lead; i < dp; i++)
|
{
|
if ((i > 0) && (dp - i) % 3 == 0)
|
{
|
// ca6[k]=',';
|
ca6[k] = dfs.getGroupingSeparator();
|
ca6[k + 1] = ca5[i];
|
k += 2;
|
} else
|
{
|
ca6[k] = ca5[i];
|
k++;
|
}
|
}
|
|
for (; i < ca5.length; i++, k++)
|
{
|
ca6[k] = ca5[i];
|
}
|
}
|
|
return ca6;
|
}
|
|
/**
|
* An intermediate routine on the way to creating
|
* an f format String. The method decides whether
|
* the input double value is an infinity,
|
* not-a-number, or a finite double and formats
|
* each type of input appropriately.
|
* @param x the double value to be formatted.
|
* @return the converted double value.
|
*/
|
private String fFormatString(double x)
|
{
|
boolean noDigits = false;
|
char[] ca6, ca7;
|
|
if (Double.isInfinite(x))
|
{
|
if (x == Double.POSITIVE_INFINITY)
|
{
|
if (leadingSign)
|
{
|
ca6 = "+Inf".toCharArray();
|
} else if (leadingSpace)
|
{
|
ca6 = " Inf".toCharArray();
|
} else
|
{
|
ca6 = "Inf".toCharArray();
|
}
|
} else
|
{
|
ca6 = "-Inf".toCharArray();
|
}
|
|
noDigits = true;
|
} else if (Double.isNaN(x))
|
{
|
if (leadingSign)
|
{
|
ca6 = "+NaN".toCharArray();
|
} else if (leadingSpace)
|
{
|
ca6 = " NaN".toCharArray();
|
} else
|
{
|
ca6 = "NaN".toCharArray();
|
}
|
|
noDigits = true;
|
} else
|
{
|
ca6 = fFormatDigits(x);
|
}
|
|
ca7 = applyFloatPadding(ca6, false);
|
|
return new String(ca7);
|
}
|
|
/**
|
* For e format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. '+' character means that the conversion
|
* will always begin with a sign (+ or -). The
|
* blank flag character means that a non-negative
|
* input will be preceded with a blank. If both a
|
* '+' and a ' ' are specified, the blank flag is
|
* ignored. The '0' flag character implies that
|
* padding to the field width will be done with
|
* zeros instead of blanks.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear after the radix character.
|
* Padding is with trailing 0s.
|
*
|
* The behavior is like printf. One (hopefully the
|
* only) exception is that the minimum number of
|
* exponent digits is 3 instead of 2 for e and E
|
* formats when the optional L is used before the
|
* e, E, g, or G conversion character. The optional
|
* L does not imply conversion to a long long
|
* double.
|
*/
|
private char[] eFormatDigits(double x, char eChar)
|
{
|
char[] ca1, ca2, ca3;
|
|
// int defaultDigits=6;
|
String sx, sxOut;
|
int i, j, k, p;
|
int n1In, n2In;
|
int expon = 0;
|
int ePos, rPos, eSize;
|
boolean minusSign = false;
|
|
if (x > 0.0)
|
{
|
sx = Double.toString(x);
|
} else if (x < 0.0)
|
{
|
sx = Double.toString(-x);
|
minusSign = true;
|
} else
|
{
|
sx = Double.toString(x);
|
|
if (sx.charAt(0) == '-')
|
{
|
minusSign = true;
|
sx = sx.substring(1);
|
}
|
}
|
|
ePos = sx.indexOf('E');
|
|
if (ePos == -1)
|
{
|
ePos = sx.indexOf('e');
|
}
|
|
rPos = sx.indexOf('.');
|
|
if (rPos != -1)
|
{
|
n1In = rPos;
|
} else if (ePos != -1)
|
{
|
n1In = ePos;
|
} else
|
{
|
n1In = sx.length();
|
}
|
|
if (rPos != -1)
|
{
|
if (ePos != -1)
|
{
|
n2In = ePos - rPos - 1;
|
} else
|
{
|
n2In = sx.length() - rPos - 1;
|
}
|
} else
|
{
|
n2In = 0;
|
}
|
|
if (ePos != -1)
|
{
|
int ie = ePos + 1;
|
|
expon = 0;
|
|
if (sx.charAt(ie) == '-')
|
{
|
for (++ie; ie < sx.length(); ie++)
|
{
|
if (sx.charAt(ie) != '0')
|
{
|
break;
|
}
|
}
|
|
if (ie < sx.length())
|
{
|
expon = -Integer.parseInt(sx.substring(ie));
|
}
|
} else
|
{
|
if (sx.charAt(ie) == '+')
|
{
|
++ie;
|
}
|
|
for (; ie < sx.length(); ie++)
|
{
|
if (sx.charAt(ie) != '0')
|
{
|
break;
|
}
|
}
|
|
if (ie < sx.length())
|
{
|
expon = Integer.parseInt(sx.substring(ie));
|
}
|
}
|
}
|
|
if (rPos != -1)
|
{
|
expon += rPos - 1;
|
}
|
|
if (precisionSet)
|
{
|
p = precision;
|
} else
|
{
|
p = defaultDigits - 1;
|
}
|
|
if ((rPos != -1) && (ePos != -1))
|
{
|
ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray();
|
} else if (rPos != -1)
|
{
|
ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray();
|
} else if (ePos != -1)
|
{
|
ca1 = sx.substring(0, ePos).toCharArray();
|
} else
|
{
|
ca1 = sx.toCharArray();
|
}
|
|
boolean carry = false;
|
int i0 = 0;
|
|
if (ca1[0] != '0')
|
{
|
i0 = 0;
|
} else
|
{
|
for (i0 = 0; i0 < ca1.length; i0++)
|
{
|
if (ca1[i0] != '0')
|
{
|
break;
|
}
|
}
|
}
|
|
if (i0 + p < ca1.length - 1)
|
{
|
carry = checkForCarry(ca1, i0 + p + 1);
|
|
if (carry)
|
{
|
carry = startSymbolicCarry(ca1, i0 + p, i0);
|
}
|
|
if (carry)
|
{
|
ca2 = new char[i0 + p + 1];
|
ca2[i0] = '1';
|
|
for (j = 0; j < i0; j++)
|
{
|
ca2[j] = '0';
|
}
|
|
for (i = i0, j = i0 + 1; j < p + 1; i++, j++)
|
{
|
ca2[j] = ca1[i];
|
}
|
|
expon++;
|
ca1 = ca2;
|
}
|
}
|
|
if ((Math.abs(expon) < 100) &&!optionalL)
|
{
|
eSize = 4;
|
} else
|
{
|
eSize = 5;
|
}
|
|
if (alternateForm ||!precisionSet || (precision != 0))
|
{
|
ca2 = new char[2 + p + eSize];
|
} else
|
{
|
ca2 = new char[1 + eSize];
|
}
|
|
if (ca1[0] != '0')
|
{
|
ca2[0] = ca1[0];
|
j = 1;
|
} else
|
{
|
for (j = 1; j < ((ePos == -1)
|
? ca1.length
|
: ePos); j++)
|
{
|
if (ca1[j] != '0')
|
{
|
break;
|
}
|
}
|
|
if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length)))
|
{
|
ca2[0] = ca1[j];
|
expon -= j;
|
j++;
|
} else
|
{
|
ca2[0] = '0';
|
j = 2;
|
}
|
}
|
|
if (alternateForm ||!precisionSet || (precision != 0))
|
{
|
ca2[1] = '.';
|
i = 2;
|
} else
|
{
|
i = 1;
|
}
|
|
for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++)
|
{
|
ca2[i] = ca1[j];
|
}
|
|
for (; i < ca2.length - eSize; i++)
|
{
|
ca2[i] = '0';
|
}
|
|
ca2[i++] = eChar;
|
|
if (expon < 0)
|
{
|
ca2[i++] = '-';
|
} else
|
{
|
ca2[i++] = '+';
|
}
|
|
expon = Math.abs(expon);
|
|
if (expon >= 100)
|
{
|
switch (expon / 100)
|
{
|
case 1 :
|
ca2[i] = '1';
|
|
break;
|
|
case 2 :
|
ca2[i] = '2';
|
|
break;
|
|
case 3 :
|
ca2[i] = '3';
|
|
break;
|
|
case 4 :
|
ca2[i] = '4';
|
|
break;
|
|
case 5 :
|
ca2[i] = '5';
|
|
break;
|
|
case 6 :
|
ca2[i] = '6';
|
|
break;
|
|
case 7 :
|
ca2[i] = '7';
|
|
break;
|
|
case 8 :
|
ca2[i] = '8';
|
|
break;
|
|
case 9 :
|
ca2[i] = '9';
|
|
break;
|
}
|
|
i++;
|
}
|
|
switch ((expon % 100) / 10)
|
{
|
case 0 :
|
ca2[i] = '0';
|
|
break;
|
|
case 1 :
|
ca2[i] = '1';
|
|
break;
|
|
case 2 :
|
ca2[i] = '2';
|
|
break;
|
|
case 3 :
|
ca2[i] = '3';
|
|
break;
|
|
case 4 :
|
ca2[i] = '4';
|
|
break;
|
|
case 5 :
|
ca2[i] = '5';
|
|
break;
|
|
case 6 :
|
ca2[i] = '6';
|
|
break;
|
|
case 7 :
|
ca2[i] = '7';
|
|
break;
|
|
case 8 :
|
ca2[i] = '8';
|
|
break;
|
|
case 9 :
|
ca2[i] = '9';
|
|
break;
|
}
|
|
i++;
|
|
switch (expon % 10)
|
{
|
case 0 :
|
ca2[i] = '0';
|
|
break;
|
|
case 1 :
|
ca2[i] = '1';
|
|
break;
|
|
case 2 :
|
ca2[i] = '2';
|
|
break;
|
|
case 3 :
|
ca2[i] = '3';
|
|
break;
|
|
case 4 :
|
ca2[i] = '4';
|
|
break;
|
|
case 5 :
|
ca2[i] = '5';
|
|
break;
|
|
case 6 :
|
ca2[i] = '6';
|
|
break;
|
|
case 7 :
|
ca2[i] = '7';
|
|
break;
|
|
case 8 :
|
ca2[i] = '8';
|
|
break;
|
|
case 9 :
|
ca2[i] = '9';
|
|
break;
|
}
|
|
int nZeros = 0;
|
|
if (!leftJustify && leadingZeros)
|
{
|
int xThousands = 0;
|
|
if (thousands)
|
{
|
int xlead = 0;
|
|
if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' '))
|
{
|
xlead = 1;
|
}
|
|
int xdp = xlead;
|
|
for (; xdp < ca2.length; xdp++)
|
{
|
if (ca2[xdp] == '.')
|
{
|
break;
|
}
|
}
|
|
xThousands = (xdp - xlead) / 3;
|
}
|
|
if (fieldWidthSet)
|
{
|
nZeros = fieldWidth - ca2.length;
|
}
|
|
if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
|
{
|
nZeros--;
|
}
|
|
nZeros -= xThousands;
|
|
if (nZeros < 0)
|
{
|
nZeros = 0;
|
}
|
}
|
|
j = 0;
|
|
if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
|
{
|
ca3 = new char[ca2.length + nZeros + 1];
|
j++;
|
} else
|
{
|
ca3 = new char[ca2.length + nZeros];
|
}
|
|
if (!minusSign)
|
{
|
if (leadingSign)
|
{
|
ca3[0] = '+';
|
}
|
|
if (leadingSpace)
|
{
|
ca3[0] = ' ';
|
}
|
} else
|
{
|
ca3[0] = '-';
|
}
|
|
for (k = 0; k < nZeros; j++, k++)
|
{
|
ca3[j] = '0';
|
}
|
|
for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++)
|
{
|
ca3[j] = ca2[i];
|
}
|
|
int lead = 0;
|
|
if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' '))
|
{
|
lead = 1;
|
}
|
|
int dp = lead;
|
|
for (; dp < ca3.length; dp++)
|
{
|
if (ca3[dp] == '.')
|
{
|
break;
|
}
|
}
|
|
int nThousands = dp / 3;
|
|
// Localize the decimal point.
|
if (dp < ca3.length)
|
{
|
ca3[dp] = dfs.getDecimalSeparator();
|
}
|
|
char[] ca4 = ca3;
|
|
if (thousands && (nThousands > 0))
|
{
|
ca4 = new char[ca3.length + nThousands + lead];
|
ca4[0] = ca3[0];
|
|
for (i = lead, k = lead; i < dp; i++)
|
{
|
if ((i > 0) && (dp - i) % 3 == 0)
|
{
|
// ca4[k]=',';
|
ca4[k] = dfs.getGroupingSeparator();
|
ca4[k + 1] = ca3[i];
|
k += 2;
|
} else
|
{
|
ca4[k] = ca3[i];
|
k++;
|
}
|
}
|
|
for (; i < ca3.length; i++, k++)
|
{
|
ca4[k] = ca3[i];
|
}
|
}
|
|
return ca4;
|
}
|
|
/**
|
* Check to see if the digits that are going to
|
* be truncated because of the precision should
|
* force a round in the preceding digits.
|
* @param ca1 the array of digits
|
* @param icarry the index of the first digit that
|
* is to be truncated from the print
|
* @return <code>true</code> if the truncation forces
|
* a round that will change the print
|
*/
|
private boolean checkForCarry(char[] ca1, int icarry)
|
{
|
boolean carry = false;
|
|
if (icarry < ca1.length)
|
{
|
if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9'))
|
{
|
carry = true;
|
} else if (ca1[icarry] == '5')
|
{
|
int ii = icarry + 1;
|
|
for (; ii < ca1.length; ii++)
|
{
|
if (ca1[ii] != '0')
|
{
|
break;
|
}
|
}
|
|
carry = ii < ca1.length;
|
|
if (!carry && (icarry > 0))
|
{
|
carry = ((ca1[icarry - 1] == '1') || (ca1[icarry - 1] == '3') || (ca1[icarry - 1] == '5')
|
|| (ca1[icarry - 1] == '7') || (ca1[icarry - 1] == '9'));
|
}
|
}
|
}
|
|
return carry;
|
}
|
|
/**
|
* Start the symbolic carry process. The process
|
* is not quite finished because the symbolic
|
* carry may change the length of the string and
|
* change the exponent (in e format).
|
* @param cLast index of the last digit changed
|
* by the round
|
* @param cFirst index of the first digit allowed
|
* to be changed by this phase of the round
|
* @return <code>true</code> if the carry forces
|
* a round that will change the print still
|
* more
|
*/
|
private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst)
|
{
|
boolean carry = true;
|
|
for (int i = cLast; carry && (i >= cFirst); i--)
|
{
|
carry = false;
|
|
switch (ca[i])
|
{
|
case '0' :
|
ca[i] = '1';
|
|
break;
|
|
case '1' :
|
ca[i] = '2';
|
|
break;
|
|
case '2' :
|
ca[i] = '3';
|
|
break;
|
|
case '3' :
|
ca[i] = '4';
|
|
break;
|
|
case '4' :
|
ca[i] = '5';
|
|
break;
|
|
case '5' :
|
ca[i] = '6';
|
|
break;
|
|
case '6' :
|
ca[i] = '7';
|
|
break;
|
|
case '7' :
|
ca[i] = '8';
|
|
break;
|
|
case '8' :
|
ca[i] = '9';
|
|
break;
|
|
case '9' :
|
ca[i] = '0';
|
carry = true;
|
|
break;
|
}
|
}
|
|
return carry;
|
}
|
|
/**
|
* An intermediate routine on the way to creating
|
* an e format String. The method decides whether
|
* the input double value is an infinity,
|
* not-a-number, or a finite double and formats
|
* each type of input appropriately.
|
* @param x the double value to be formatted.
|
* @param eChar an 'e' or 'E' to use in the
|
* converted double value.
|
* @return the converted double value.
|
*/
|
private String eFormatString(double x, char eChar)
|
{
|
boolean noDigits = false;
|
char[] ca4, ca5;
|
|
if (Double.isInfinite(x))
|
{
|
if (x == Double.POSITIVE_INFINITY)
|
{
|
if (leadingSign)
|
{
|
ca4 = "+Inf".toCharArray();
|
} else if (leadingSpace)
|
{
|
ca4 = " Inf".toCharArray();
|
} else
|
{
|
ca4 = "Inf".toCharArray();
|
}
|
} else
|
{
|
ca4 = "-Inf".toCharArray();
|
}
|
|
noDigits = true;
|
} else if (Double.isNaN(x))
|
{
|
if (leadingSign)
|
{
|
ca4 = "+NaN".toCharArray();
|
} else if (leadingSpace)
|
{
|
ca4 = " NaN".toCharArray();
|
} else
|
{
|
ca4 = "NaN".toCharArray();
|
}
|
|
noDigits = true;
|
} else
|
{
|
ca4 = eFormatDigits(x, eChar);
|
}
|
|
ca5 = applyFloatPadding(ca4, false);
|
|
return new String(ca5);
|
}
|
|
/**
|
* Apply zero or blank, left or right padding.
|
* @param ca4 array of characters before padding is
|
* finished
|
* @param noDigits NaN or signed Inf
|
* @return a padded array of characters
|
*/
|
private char[] applyFloatPadding(char[] ca4, boolean noDigits)
|
{
|
char[] ca5 = ca4;
|
|
if (fieldWidthSet)
|
{
|
int i, j, nBlanks;
|
|
if (leftJustify)
|
{
|
nBlanks = fieldWidth - ca4.length;
|
|
if (nBlanks > 0)
|
{
|
ca5 = new char[ca4.length + nBlanks];
|
|
for (i = 0; i < ca4.length; i++)
|
{
|
ca5[i] = ca4[i];
|
}
|
|
for (j = 0; j < nBlanks; j++, i++)
|
{
|
ca5[i] = ' ';
|
}
|
}
|
} else if (!leadingZeros || noDigits)
|
{
|
nBlanks = fieldWidth - ca4.length;
|
|
if (nBlanks > 0)
|
{
|
ca5 = new char[ca4.length + nBlanks];
|
|
for (i = 0; i < nBlanks; i++)
|
{
|
ca5[i] = ' ';
|
}
|
|
for (j = 0; j < ca4.length; i++, j++)
|
{
|
ca5[i] = ca4[j];
|
}
|
}
|
} else if (leadingZeros)
|
{
|
nBlanks = fieldWidth - ca4.length;
|
|
if (nBlanks > 0)
|
{
|
ca5 = new char[ca4.length + nBlanks];
|
i = 0;
|
j = 0;
|
|
if (ca4[0] == '-')
|
{
|
ca5[0] = '-';
|
i++;
|
j++;
|
}
|
|
for (int k = 0; k < nBlanks; i++, k++)
|
{
|
ca5[i] = '0';
|
}
|
|
for (; j < ca4.length; i++, j++)
|
{
|
ca5[i] = ca4[j];
|
}
|
}
|
}
|
}
|
|
return ca5;
|
}
|
|
/**
|
* Format method for the f conversion character.
|
* @param x the double to format.
|
* @return the formatted String.
|
*/
|
private String printFFormat(double x)
|
{
|
return fFormatString(x);
|
}
|
|
/**
|
* Format method for the e or E conversion
|
* character.
|
* @param x the double to format.
|
* @return the formatted String.
|
*/
|
private String printEFormat(double x)
|
{
|
if (conversionCharacter == 'e')
|
{
|
return eFormatString(x, 'e');
|
} else
|
{
|
return eFormatString(x, 'E');
|
}
|
}
|
|
/**
|
* Format method for the g conversion character.
|
*
|
* For g format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. '+' character means that the conversion
|
* will always begin with a sign (+ or -). The
|
* blank flag character means that a non-negative
|
* input will be preceded with a blank. If both a
|
* '+' and a ' ' are specified, the blank flag is
|
* ignored. The '0' flag character implies that
|
* padding to the field width will be done with
|
* zeros instead of blanks.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear after the radix character.
|
* Padding is with trailing 0s.
|
* @param x the double to format.
|
* @return the formatted String.
|
*/
|
private String printGFormat(double x)
|
{
|
String sx, sy, sz, ret;
|
int savePrecision = precision;
|
int i;
|
char[] ca4, ca5;
|
boolean noDigits = false;
|
|
if (Double.isInfinite(x))
|
{
|
if (x == Double.POSITIVE_INFINITY)
|
{
|
if (leadingSign)
|
{
|
ca4 = "+Inf".toCharArray();
|
} else if (leadingSpace)
|
{
|
ca4 = " Inf".toCharArray();
|
} else
|
{
|
ca4 = "Inf".toCharArray();
|
}
|
} else
|
{
|
ca4 = "-Inf".toCharArray();
|
}
|
|
noDigits = true;
|
} else if (Double.isNaN(x))
|
{
|
if (leadingSign)
|
{
|
ca4 = "+NaN".toCharArray();
|
} else if (leadingSpace)
|
{
|
ca4 = " NaN".toCharArray();
|
} else
|
{
|
ca4 = "NaN".toCharArray();
|
}
|
|
noDigits = true;
|
} else
|
{
|
if (!precisionSet)
|
{
|
precision = defaultDigits;
|
}
|
|
if (precision == 0)
|
{
|
precision = 1;
|
}
|
|
int ePos = -1;
|
|
if (conversionCharacter == 'g')
|
{
|
sx = eFormatString(x, 'e').trim();
|
ePos = sx.indexOf('e');
|
} else
|
{
|
sx = eFormatString(x, 'E').trim();
|
ePos = sx.indexOf('E');
|
}
|
|
i = ePos + 1;
|
|
int expon = 0;
|
|
if (sx.charAt(i) == '-')
|
{
|
for (++i; i < sx.length(); i++)
|
{
|
if (sx.charAt(i) != '0')
|
{
|
break;
|
}
|
}
|
|
if (i < sx.length())
|
{
|
expon = -Integer.parseInt(sx.substring(i));
|
}
|
} else
|
{
|
if (sx.charAt(i) == '+')
|
{
|
++i;
|
}
|
|
for (; i < sx.length(); i++)
|
{
|
if (sx.charAt(i) != '0')
|
{
|
break;
|
}
|
}
|
|
if (i < sx.length())
|
{
|
expon = Integer.parseInt(sx.substring(i));
|
}
|
}
|
|
// Trim trailing zeros.
|
// If the radix character is not followed by
|
// a digit, trim it, too.
|
if (!alternateForm)
|
{
|
if ((expon >= -4) && (expon < precision))
|
{
|
sy = fFormatString(x).trim();
|
} else
|
{
|
sy = sx.substring(0, ePos);
|
}
|
|
i = sy.length() - 1;
|
|
for (; i >= 0; i--)
|
{
|
if (sy.charAt(i) != '0')
|
{
|
break;
|
}
|
}
|
|
if ((i >= 0) && (sy.charAt(i) == '.'))
|
{
|
i--;
|
}
|
|
if (i == -1)
|
{
|
sz = "0";
|
} else if (!Character.isDigit(sy.charAt(i)))
|
{
|
sz = sy.substring(0, i + 1) + "0";
|
} else
|
{
|
sz = sy.substring(0, i + 1);
|
}
|
|
if ((expon >= -4) && (expon < precision))
|
{
|
ret = sz;
|
} else
|
{
|
ret = sz + sx.substring(ePos);
|
}
|
} else
|
{
|
if ((expon >= -4) && (expon < precision))
|
{
|
ret = fFormatString(x).trim();
|
} else
|
{
|
ret = sx;
|
}
|
}
|
|
// leading space was trimmed off during
|
// construction
|
if (leadingSpace)
|
{
|
if (x >= 0)
|
{
|
ret = " " + ret;
|
}
|
}
|
|
ca4 = ret.toCharArray();
|
}
|
|
// Pad with blanks or zeros.
|
ca5 = applyFloatPadding(ca4, false);
|
precision = savePrecision;
|
|
return new String(ca5);
|
}
|
|
/**
|
* Format method for the d conversion specifer and
|
* short argument.
|
*
|
* For d format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. A '+' character means that the conversion
|
* will always begin with a sign (+ or -). The
|
* blank flag character means that a non-negative
|
* input will be preceded with a blank. If both a
|
* '+' and a ' ' are specified, the blank flag is
|
* ignored. The '0' flag character implies that
|
* padding to the field width will be done with
|
* zeros instead of blanks.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the short to format.
|
* @return the formatted String.
|
*/
|
private String printDFormat(short x)
|
{
|
return printDFormat(Short.toString(x));
|
}
|
|
/**
|
* Format method for the d conversion character and
|
* long argument.
|
*
|
* For d format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. A '+' character means that the conversion
|
* will always begin with a sign (+ or -). The
|
* blank flag character means that a non-negative
|
* input will be preceded with a blank. If both a
|
* '+' and a ' ' are specified, the blank flag is
|
* ignored. The '0' flag character implies that
|
* padding to the field width will be done with
|
* zeros instead of blanks.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the long to format.
|
* @return the formatted String.
|
*/
|
private String printDFormat(long x)
|
{
|
return printDFormat(Long.toString(x));
|
}
|
|
/**
|
* Format method for the d conversion character and
|
* int argument.
|
*
|
* For d format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. A '+' character means that the conversion
|
* will always begin with a sign (+ or -). The
|
* blank flag character means that a non-negative
|
* input will be preceded with a blank. If both a
|
* '+' and a ' ' are specified, the blank flag is
|
* ignored. The '0' flag character implies that
|
* padding to the field width will be done with
|
* zeros instead of blanks.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the int to format.
|
* @return the formatted String.
|
*/
|
private String printDFormat(int x)
|
{
|
return printDFormat(Integer.toString(x));
|
}
|
|
/**
|
* Utility method for formatting using the d
|
* conversion character.
|
* @param sx the String to format, the result of
|
* converting a short, int, or long to a
|
* String.
|
* @return the formatted String.
|
*/
|
private String printDFormat(String sx)
|
{
|
int nLeadingZeros = 0;
|
int nBlanks = 0,
|
n = 0;
|
int i = 0,
|
jFirst = 0;
|
boolean neg = sx.charAt(0) == '-';
|
|
if (sx.equals("0") && precisionSet && (precision == 0))
|
{
|
sx = "";
|
}
|
|
if (!neg)
|
{
|
if (precisionSet && (sx.length() < precision))
|
{
|
nLeadingZeros = precision - sx.length();
|
}
|
} else
|
{
|
if (precisionSet && (sx.length() - 1) < precision)
|
{
|
nLeadingZeros = precision - sx.length() + 1;
|
}
|
}
|
|
if (nLeadingZeros < 0)
|
{
|
nLeadingZeros = 0;
|
}
|
|
if (fieldWidthSet)
|
{
|
nBlanks = fieldWidth - nLeadingZeros - sx.length();
|
|
if (!neg && (leadingSign || leadingSpace))
|
{
|
nBlanks--;
|
}
|
}
|
|
if (nBlanks < 0)
|
{
|
nBlanks = 0;
|
}
|
|
if (leadingSign)
|
{
|
n++;
|
} else if (leadingSpace)
|
{
|
n++;
|
}
|
|
n += nBlanks;
|
n += nLeadingZeros;
|
n += sx.length();
|
|
char[] ca = new char[n];
|
|
if (leftJustify)
|
{
|
if (neg)
|
{
|
ca[i++] = '-';
|
} else if (leadingSign)
|
{
|
ca[i++] = '+';
|
} else if (leadingSpace)
|
{
|
ca[i++] = ' ';
|
}
|
|
char[] csx = sx.toCharArray();
|
|
jFirst = neg
|
? 1
|
: 0;
|
|
for (int j = 0; j < nLeadingZeros; i++, j++)
|
{
|
ca[i] = '0';
|
}
|
|
for (int j = jFirst; j < csx.length; j++, i++)
|
{
|
ca[i] = csx[j];
|
}
|
|
for (int j = 0; j < nBlanks; i++, j++)
|
{
|
ca[i] = ' ';
|
}
|
} else
|
{
|
if (!leadingZeros)
|
{
|
for (i = 0; i < nBlanks; i++)
|
{
|
ca[i] = ' ';
|
}
|
|
if (neg)
|
{
|
ca[i++] = '-';
|
} else if (leadingSign)
|
{
|
ca[i++] = '+';
|
} else if (leadingSpace)
|
{
|
ca[i++] = ' ';
|
}
|
} else
|
{
|
if (neg)
|
{
|
ca[i++] = '-';
|
} else if (leadingSign)
|
{
|
ca[i++] = '+';
|
} else if (leadingSpace)
|
{
|
ca[i++] = ' ';
|
}
|
|
for (int j = 0; j < nBlanks; j++, i++)
|
{
|
ca[i] = '0';
|
}
|
}
|
|
for (int j = 0; j < nLeadingZeros; j++, i++)
|
{
|
ca[i] = '0';
|
}
|
|
char[] csx = sx.toCharArray();
|
|
jFirst = neg
|
? 1
|
: 0;
|
|
for (int j = jFirst; j < csx.length; j++, i++)
|
{
|
ca[i] = csx[j];
|
}
|
}
|
|
return new String(ca);
|
}
|
|
/**
|
* Format method for the x conversion character and
|
* short argument.
|
*
|
* For x format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. The '#' flag character means to lead with
|
* '0x'.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the short to format.
|
* @return the formatted String.
|
*/
|
private String printXFormat(short x)
|
{
|
String sx = null;
|
|
if (x == Short.MIN_VALUE)
|
{
|
sx = "8000";
|
} else if (x < 0)
|
{
|
String t;
|
|
if (x == Short.MIN_VALUE)
|
{
|
t = "0";
|
} else
|
{
|
t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16);
|
|
if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f'))
|
{
|
t = t.substring(16, 32);
|
}
|
}
|
|
switch (t.length())
|
{
|
case 1 :
|
sx = "800" + t;
|
|
break;
|
|
case 2 :
|
sx = "80" + t;
|
|
break;
|
|
case 3 :
|
sx = "8" + t;
|
|
break;
|
|
case 4 :
|
switch (t.charAt(0))
|
{
|
case '1' :
|
sx = "9" + t.substring(1, 4);
|
|
break;
|
|
case '2' :
|
sx = "a" + t.substring(1, 4);
|
|
break;
|
|
case '3' :
|
sx = "b" + t.substring(1, 4);
|
|
break;
|
|
case '4' :
|
sx = "c" + t.substring(1, 4);
|
|
break;
|
|
case '5' :
|
sx = "d" + t.substring(1, 4);
|
|
break;
|
|
case '6' :
|
sx = "e" + t.substring(1, 4);
|
|
break;
|
|
case '7' :
|
sx = "f" + t.substring(1, 4);
|
|
break;
|
}
|
|
break;
|
}
|
} else
|
{
|
sx = Integer.toString((int) x, 16);
|
}
|
|
return printXFormat(sx);
|
}
|
|
/**
|
* Format method for the x conversion character and
|
* long argument.
|
*
|
* For x format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. The '#' flag character means to lead with
|
* '0x'.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the long to format.
|
* @return the formatted String.
|
*/
|
private String printXFormat(long x)
|
{
|
String sx = null;
|
|
if (x == Long.MIN_VALUE)
|
{
|
sx = "8000000000000000";
|
} else if (x < 0)
|
{
|
String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16);
|
|
switch (t.length())
|
{
|
case 1 :
|
sx = "800000000000000" + t;
|
|
break;
|
|
case 2 :
|
sx = "80000000000000" + t;
|
|
break;
|
|
case 3 :
|
sx = "8000000000000" + t;
|
|
break;
|
|
case 4 :
|
sx = "800000000000" + t;
|
|
break;
|
|
case 5 :
|
sx = "80000000000" + t;
|
|
break;
|
|
case 6 :
|
sx = "8000000000" + t;
|
|
break;
|
|
case 7 :
|
sx = "800000000" + t;
|
|
break;
|
|
case 8 :
|
sx = "80000000" + t;
|
|
break;
|
|
case 9 :
|
sx = "8000000" + t;
|
|
break;
|
|
case 10 :
|
sx = "800000" + t;
|
|
break;
|
|
case 11 :
|
sx = "80000" + t;
|
|
break;
|
|
case 12 :
|
sx = "8000" + t;
|
|
break;
|
|
case 13 :
|
sx = "800" + t;
|
|
break;
|
|
case 14 :
|
sx = "80" + t;
|
|
break;
|
|
case 15 :
|
sx = "8" + t;
|
|
break;
|
|
case 16 :
|
switch (t.charAt(0))
|
{
|
case '1' :
|
sx = "9" + t.substring(1, 16);
|
|
break;
|
|
case '2' :
|
sx = "a" + t.substring(1, 16);
|
|
break;
|
|
case '3' :
|
sx = "b" + t.substring(1, 16);
|
|
break;
|
|
case '4' :
|
sx = "c" + t.substring(1, 16);
|
|
break;
|
|
case '5' :
|
sx = "d" + t.substring(1, 16);
|
|
break;
|
|
case '6' :
|
sx = "e" + t.substring(1, 16);
|
|
break;
|
|
case '7' :
|
sx = "f" + t.substring(1, 16);
|
|
break;
|
}
|
|
break;
|
}
|
} else
|
{
|
sx = Long.toString(x, 16);
|
}
|
|
return printXFormat(sx);
|
}
|
|
/**
|
* Format method for the x conversion character and
|
* int argument.
|
*
|
* For x format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. The '#' flag character means to lead with
|
* '0x'.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the int to format.
|
* @return the formatted String.
|
*/
|
private String printXFormat(int x)
|
{
|
String sx = null;
|
|
if (x == Integer.MIN_VALUE)
|
{
|
sx = "80000000";
|
} else if (x < 0)
|
{
|
String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16);
|
|
switch (t.length())
|
{
|
case 1 :
|
sx = "8000000" + t;
|
|
break;
|
|
case 2 :
|
sx = "800000" + t;
|
|
break;
|
|
case 3 :
|
sx = "80000" + t;
|
|
break;
|
|
case 4 :
|
sx = "8000" + t;
|
|
break;
|
|
case 5 :
|
sx = "800" + t;
|
|
break;
|
|
case 6 :
|
sx = "80" + t;
|
|
break;
|
|
case 7 :
|
sx = "8" + t;
|
|
break;
|
|
case 8 :
|
switch (t.charAt(0))
|
{
|
case '1' :
|
sx = "9" + t.substring(1, 8);
|
|
break;
|
|
case '2' :
|
sx = "a" + t.substring(1, 8);
|
|
break;
|
|
case '3' :
|
sx = "b" + t.substring(1, 8);
|
|
break;
|
|
case '4' :
|
sx = "c" + t.substring(1, 8);
|
|
break;
|
|
case '5' :
|
sx = "d" + t.substring(1, 8);
|
|
break;
|
|
case '6' :
|
sx = "e" + t.substring(1, 8);
|
|
break;
|
|
case '7' :
|
sx = "f" + t.substring(1, 8);
|
|
break;
|
}
|
|
break;
|
}
|
} else
|
{
|
sx = Integer.toString(x, 16);
|
}
|
|
return printXFormat(sx);
|
}
|
|
/**
|
* Utility method for formatting using the x
|
* conversion character.
|
* @param sx the String to format, the result of
|
* converting a short, int, or long to a
|
* String.
|
* @return the formatted String.
|
*/
|
private String printXFormat(String sx)
|
{
|
int nLeadingZeros = 0;
|
int nBlanks = 0;
|
|
if (sx.equals("0") && precisionSet && (precision == 0))
|
{
|
sx = "";
|
}
|
|
if (precisionSet)
|
{
|
nLeadingZeros = precision - sx.length();
|
}
|
|
if (nLeadingZeros < 0)
|
{
|
nLeadingZeros = 0;
|
}
|
|
if (fieldWidthSet)
|
{
|
nBlanks = fieldWidth - nLeadingZeros - sx.length();
|
|
if (alternateForm)
|
{
|
nBlanks = nBlanks - 2;
|
}
|
}
|
|
if (nBlanks < 0)
|
{
|
nBlanks = 0;
|
}
|
|
int n = 0;
|
|
if (alternateForm)
|
{
|
n += 2;
|
}
|
|
n += nLeadingZeros;
|
n += sx.length();
|
n += nBlanks;
|
|
char[] ca = new char[n];
|
int i = 0;
|
|
if (leftJustify)
|
{
|
if (alternateForm)
|
{
|
ca[i++] = '0';
|
ca[i++] = 'x';
|
}
|
|
for (int j = 0; j < nLeadingZeros; j++, i++)
|
{
|
ca[i] = '0';
|
}
|
|
char[] csx = sx.toCharArray();
|
|
for (int j = 0; j < csx.length; j++, i++)
|
{
|
ca[i] = csx[j];
|
}
|
|
for (int j = 0; j < nBlanks; j++, i++)
|
{
|
ca[i] = ' ';
|
}
|
} else
|
{
|
if (!leadingZeros)
|
{
|
for (int j = 0; j < nBlanks; j++, i++)
|
{
|
ca[i] = ' ';
|
}
|
}
|
|
if (alternateForm)
|
{
|
ca[i++] = '0';
|
ca[i++] = 'x';
|
}
|
|
if (leadingZeros)
|
{
|
for (int j = 0; j < nBlanks; j++, i++)
|
{
|
ca[i] = '0';
|
}
|
}
|
|
for (int j = 0; j < nLeadingZeros; j++, i++)
|
{
|
ca[i] = '0';
|
}
|
|
char[] csx = sx.toCharArray();
|
|
for (int j = 0; j < csx.length; j++, i++)
|
{
|
ca[i] = csx[j];
|
}
|
}
|
|
String caReturn = new String(ca);
|
|
if (conversionCharacter == 'X')
|
{
|
caReturn = caReturn.toUpperCase();
|
}
|
|
return caReturn;
|
}
|
|
/**
|
* Format method for the o conversion character and
|
* short argument.
|
*
|
* For o format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. The '#' flag character means that the
|
* output begins with a leading 0 and the precision
|
* is increased by 1.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the short to format.
|
* @return the formatted String.
|
*/
|
private String printOFormat(short x)
|
{
|
String sx = null;
|
|
if (x == Short.MIN_VALUE)
|
{
|
sx = "100000";
|
} else if (x < 0)
|
{
|
String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8);
|
|
switch (t.length())
|
{
|
case 1 :
|
sx = "10000" + t;
|
|
break;
|
|
case 2 :
|
sx = "1000" + t;
|
|
break;
|
|
case 3 :
|
sx = "100" + t;
|
|
break;
|
|
case 4 :
|
sx = "10" + t;
|
|
break;
|
|
case 5 :
|
sx = "1" + t;
|
|
break;
|
}
|
} else
|
{
|
sx = Integer.toString((int) x, 8);
|
}
|
|
return printOFormat(sx);
|
}
|
|
/**
|
* Format method for the o conversion character and
|
* long argument.
|
*
|
* For o format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. The '#' flag character means that the
|
* output begins with a leading 0 and the precision
|
* is increased by 1.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the long to format.
|
* @return the formatted String.
|
*/
|
private String printOFormat(long x)
|
{
|
String sx = null;
|
|
if (x == Long.MIN_VALUE)
|
{
|
sx = "1000000000000000000000";
|
} else if (x < 0)
|
{
|
String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8);
|
|
switch (t.length())
|
{
|
case 1 :
|
sx = "100000000000000000000" + t;
|
|
break;
|
|
case 2 :
|
sx = "10000000000000000000" + t;
|
|
break;
|
|
case 3 :
|
sx = "1000000000000000000" + t;
|
|
break;
|
|
case 4 :
|
sx = "100000000000000000" + t;
|
|
break;
|
|
case 5 :
|
sx = "10000000000000000" + t;
|
|
break;
|
|
case 6 :
|
sx = "1000000000000000" + t;
|
|
break;
|
|
case 7 :
|
sx = "100000000000000" + t;
|
|
break;
|
|
case 8 :
|
sx = "10000000000000" + t;
|
|
break;
|
|
case 9 :
|
sx = "1000000000000" + t;
|
|
break;
|
|
case 10 :
|
sx = "100000000000" + t;
|
|
break;
|
|
case 11 :
|
sx = "10000000000" + t;
|
|
break;
|
|
case 12 :
|
sx = "1000000000" + t;
|
|
break;
|
|
case 13 :
|
sx = "100000000" + t;
|
|
break;
|
|
case 14 :
|
sx = "10000000" + t;
|
|
break;
|
|
case 15 :
|
sx = "1000000" + t;
|
|
break;
|
|
case 16 :
|
sx = "100000" + t;
|
|
break;
|
|
case 17 :
|
sx = "10000" + t;
|
|
break;
|
|
case 18 :
|
sx = "1000" + t;
|
|
break;
|
|
case 19 :
|
sx = "100" + t;
|
|
break;
|
|
case 20 :
|
sx = "10" + t;
|
|
break;
|
|
case 21 :
|
sx = "1" + t;
|
|
break;
|
}
|
} else
|
{
|
sx = Long.toString(x, 8);
|
}
|
|
return printOFormat(sx);
|
}
|
|
/**
|
* Format method for the o conversion character and
|
* int argument.
|
*
|
* For o format, the flag character '-', means that
|
* the output should be left justified within the
|
* field. The default is to pad with blanks on the
|
* left. The '#' flag character means that the
|
* output begins with a leading 0 and the precision
|
* is increased by 1.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is to
|
* add no padding. Padding is with blanks by
|
* default.
|
*
|
* The precision, if set, is the minimum number of
|
* digits to appear. Padding is with leading 0s.
|
* @param x the int to format.
|
* @return the formatted String.
|
*/
|
private String printOFormat(int x)
|
{
|
String sx = null;
|
|
if (x == Integer.MIN_VALUE)
|
{
|
sx = "20000000000";
|
} else if (x < 0)
|
{
|
String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8);
|
|
switch (t.length())
|
{
|
case 1 :
|
sx = "2000000000" + t;
|
|
break;
|
|
case 2 :
|
sx = "200000000" + t;
|
|
break;
|
|
case 3 :
|
sx = "20000000" + t;
|
|
break;
|
|
case 4 :
|
sx = "2000000" + t;
|
|
break;
|
|
case 5 :
|
sx = "200000" + t;
|
|
break;
|
|
case 6 :
|
sx = "20000" + t;
|
|
break;
|
|
case 7 :
|
sx = "2000" + t;
|
|
break;
|
|
case 8 :
|
sx = "200" + t;
|
|
break;
|
|
case 9 :
|
sx = "20" + t;
|
|
break;
|
|
case 10 :
|
sx = "2" + t;
|
|
break;
|
|
case 11 :
|
sx = "3" + t.substring(1);
|
|
break;
|
}
|
} else
|
{
|
sx = Integer.toString(x, 8);
|
}
|
|
return printOFormat(sx);
|
}
|
|
/**
|
* Utility method for formatting using the o
|
* conversion character.
|
* @param sx the String to format, the result of
|
* converting a short, int, or long to a
|
* String.
|
* @return the formatted String.
|
*/
|
private String printOFormat(String sx)
|
{
|
int nLeadingZeros = 0;
|
int nBlanks = 0;
|
|
if (sx.equals("0") && precisionSet && (precision == 0))
|
{
|
sx = "";
|
}
|
|
if (precisionSet)
|
{
|
nLeadingZeros = precision - sx.length();
|
}
|
|
if (alternateForm)
|
{
|
nLeadingZeros++;
|
}
|
|
if (nLeadingZeros < 0)
|
{
|
nLeadingZeros = 0;
|
}
|
|
if (fieldWidthSet)
|
{
|
nBlanks = fieldWidth - nLeadingZeros - sx.length();
|
}
|
|
if (nBlanks < 0)
|
{
|
nBlanks = 0;
|
}
|
|
int n = nLeadingZeros + sx.length() + nBlanks;
|
char[] ca = new char[n];
|
int i;
|
|
if (leftJustify)
|
{
|
for (i = 0; i < nLeadingZeros; i++)
|
{
|
ca[i] = '0';
|
}
|
|
char[] csx = sx.toCharArray();
|
|
for (int j = 0; j < csx.length; j++, i++)
|
{
|
ca[i] = csx[j];
|
}
|
|
for (int j = 0; j < nBlanks; j++, i++)
|
{
|
ca[i] = ' ';
|
}
|
} else
|
{
|
if (leadingZeros)
|
{
|
for (i = 0; i < nBlanks; i++)
|
{
|
ca[i] = '0';
|
}
|
} else
|
{
|
for (i = 0; i < nBlanks; i++)
|
{
|
ca[i] = ' ';
|
}
|
}
|
|
for (int j = 0; j < nLeadingZeros; j++, i++)
|
{
|
ca[i] = '0';
|
}
|
|
char[] csx = sx.toCharArray();
|
|
for (int j = 0; j < csx.length; j++, i++)
|
{
|
ca[i] = csx[j];
|
}
|
}
|
|
return new String(ca);
|
}
|
|
/**
|
* Format method for the c conversion character and
|
* char argument.
|
*
|
* The only flag character that affects c format is
|
* the '-', meaning that the output should be left
|
* justified within the field. The default is to
|
* pad with blanks on the left.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. Padding is with
|
* blanks by default. The default width is 1.
|
*
|
* The precision, if set, is ignored.
|
* @param x the char to format.
|
* @return the formatted String.
|
*/
|
private String printCFormat(char x)
|
{
|
int nPrint = 1;
|
int width = fieldWidth;
|
|
if (!fieldWidthSet)
|
{
|
width = nPrint;
|
}
|
|
char[] ca = new char[width];
|
int i = 0;
|
|
if (leftJustify)
|
{
|
ca[0] = x;
|
|
for (i = 1; i <= width - nPrint; i++)
|
{
|
ca[i] = ' ';
|
}
|
} else
|
{
|
for (i = 0; i < width - nPrint; i++)
|
{
|
ca[i] = ' ';
|
}
|
|
ca[i] = x;
|
}
|
|
return new String(ca);
|
}
|
|
/**
|
* Format method for the s conversion character and
|
* String argument.
|
*
|
* The only flag character that affects s format is
|
* the '-', meaning that the output should be left
|
* justified within the field. The default is to
|
* pad with blanks on the left.
|
*
|
* The field width is treated as the minimum number
|
* of characters to be printed. The default is the
|
* smaller of the number of characters in the the
|
* input and the precision. Padding is with blanks
|
* by default.
|
*
|
* The precision, if set, specifies the maximum
|
* number of characters to be printed from the
|
* string. A null digit string is treated
|
* as a 0. The default is not to set a maximum
|
* number of characters to be printed.
|
* @param x the String to format.
|
* @return the formatted String.
|
*/
|
private String printSFormat(String x)
|
{
|
int nPrint = x.length();
|
int width = fieldWidth;
|
|
if (precisionSet && (nPrint > precision))
|
{
|
nPrint = precision;
|
}
|
|
if (!fieldWidthSet)
|
{
|
width = nPrint;
|
}
|
|
int n = 0;
|
|
if (width > nPrint)
|
{
|
n += width - nPrint;
|
}
|
|
if (nPrint >= x.length())
|
{
|
n += x.length();
|
} else
|
{
|
n += nPrint;
|
}
|
|
char[] ca = new char[n];
|
int i = 0;
|
|
if (leftJustify)
|
{
|
if (nPrint >= x.length())
|
{
|
char[] csx = x.toCharArray();
|
|
for (i = 0; i < x.length(); i++)
|
{
|
ca[i] = csx[i];
|
}
|
} else
|
{
|
char[] csx = x.substring(0, nPrint).toCharArray();
|
|
for (i = 0; i < nPrint; i++)
|
{
|
ca[i] = csx[i];
|
}
|
}
|
|
for (int j = 0; j < width - nPrint; j++, i++)
|
{
|
ca[i] = ' ';
|
}
|
} else
|
{
|
for (i = 0; i < width - nPrint; i++)
|
{
|
ca[i] = ' ';
|
}
|
|
if (nPrint >= x.length())
|
{
|
char[] csx = x.toCharArray();
|
|
for (int j = 0; j < x.length(); i++, j++)
|
{
|
ca[i] = csx[j];
|
}
|
} else
|
{
|
char[] csx = x.substring(0, nPrint).toCharArray();
|
|
for (int j = 0; j < nPrint; i++, j++)
|
{
|
ca[i] = csx[j];
|
}
|
}
|
}
|
|
return new String(ca);
|
}
|
|
/**
|
* Check for a conversion character. If it is
|
* there, store it.
|
* @return <code>true</code> if the conversion
|
* character is there, and
|
* <code>false</code> otherwise.
|
*/
|
private boolean setConversionCharacter()
|
{
|
/* idfgGoxXeEcs */
|
boolean ret = false;
|
|
conversionCharacter = '\0';
|
|
if (pos < fmt.length())
|
{
|
char c = fmt.charAt(pos);
|
|
if ((c == 'i') || (c == 'd') || (c == 'f') || (c == 'g') || (c == 'G') || (c == 'o') || (c == 'x') || (c == 'X')
|
|| (c == 'e') || (c == 'E') || (c == 'c') || (c == 's') || (c == '%'))
|
{
|
conversionCharacter = c;
|
pos++;
|
ret = true;
|
}
|
}
|
|
return ret;
|
}
|
|
/**
|
* Check for an h, l, or L in a format. An L is
|
* used to control the minimum number of digits
|
* in an exponent when using floating point
|
* formats. An l or h is used to control
|
* conversion of the input to a long or short,
|
* respectively, before formatting. If any of
|
* these is present, store them.
|
*/
|
private void setOptionalHL()
|
{
|
optionalh = false;
|
optionall = false;
|
optionalL = false;
|
|
if (pos < fmt.length())
|
{
|
char c = fmt.charAt(pos);
|
|
if (c == 'h')
|
{
|
optionalh = true;
|
pos++;
|
} else if (c == 'l')
|
{
|
optionall = true;
|
pos++;
|
} else if (c == 'L')
|
{
|
optionalL = true;
|
pos++;
|
}
|
}
|
}
|
|
/**
|
* Set the precision.
|
*/
|
private void setPrecision()
|
{
|
int firstPos = pos;
|
|
precisionSet = false;
|
|
if ((pos < fmt.length()) && (fmt.charAt(pos) == '.'))
|
{
|
pos++;
|
|
if ((pos < fmt.length()) && (fmt.charAt(pos) == '*'))
|
{
|
pos++;
|
|
if (!setPrecisionArgPosition())
|
{
|
variablePrecision = true;
|
precisionSet = true;
|
}
|
|
return;
|
} else
|
{
|
while (pos < fmt.length())
|
{
|
char c = fmt.charAt(pos);
|
|
if (Character.isDigit(c))
|
{
|
pos++;
|
} else
|
{
|
break;
|
}
|
}
|
|
if (pos > firstPos + 1)
|
{
|
String sz = fmt.substring(firstPos + 1, pos);
|
|
precision = Integer.parseInt(sz);
|
precisionSet = true;
|
}
|
}
|
}
|
}
|
|
/**
|
* Set the field width.
|
*/
|
private void setFieldWidth()
|
{
|
int firstPos = pos;
|
|
fieldWidth = 0;
|
fieldWidthSet = false;
|
|
if ((pos < fmt.length()) && (fmt.charAt(pos) == '*'))
|
{
|
pos++;
|
|
if (!setFieldWidthArgPosition())
|
{
|
variableFieldWidth = true;
|
fieldWidthSet = true;
|
}
|
} else
|
{
|
while (pos < fmt.length())
|
{
|
char c = fmt.charAt(pos);
|
|
if (Character.isDigit(c))
|
{
|
pos++;
|
} else
|
{
|
break;
|
}
|
}
|
|
if ((firstPos < pos) && (firstPos < fmt.length()))
|
{
|
String sz = fmt.substring(firstPos, pos);
|
|
fieldWidth = Integer.parseInt(sz);
|
fieldWidthSet = true;
|
}
|
}
|
}
|
|
/**
|
* Store the digits <code>n</code> in %n$ forms.
|
*/
|
private void setArgPosition()
|
{
|
int xPos;
|
|
for (xPos = pos; xPos < fmt.length(); xPos++)
|
{
|
if (!Character.isDigit(fmt.charAt(xPos)))
|
{
|
break;
|
}
|
}
|
|
if ((xPos > pos) && (xPos < fmt.length()))
|
{
|
if (fmt.charAt(xPos) == '$')
|
{
|
positionalSpecification = true;
|
argumentPosition = Integer.parseInt(fmt.substring(pos, xPos));
|
pos = xPos + 1;
|
}
|
}
|
}
|
|
/**
|
* Store the digits <code>n</code> in *n$ forms.
|
*/
|
private boolean setFieldWidthArgPosition()
|
{
|
boolean ret = false;
|
int xPos;
|
|
for (xPos = pos; xPos < fmt.length(); xPos++)
|
{
|
if (!Character.isDigit(fmt.charAt(xPos)))
|
{
|
break;
|
}
|
}
|
|
if ((xPos > pos) && (xPos < fmt.length()))
|
{
|
if (fmt.charAt(xPos) == '$')
|
{
|
positionalFieldWidth = true;
|
argumentPositionForFieldWidth = Integer.parseInt(fmt.substring(pos, xPos));
|
pos = xPos + 1;
|
ret = true;
|
}
|
}
|
|
return ret;
|
}
|
|
/**
|
* Store the digits <code>n</code> in *n$ forms.
|
*/
|
private boolean setPrecisionArgPosition()
|
{
|
boolean ret = false;
|
int xPos;
|
|
for (xPos = pos; xPos < fmt.length(); xPos++)
|
{
|
if (!Character.isDigit(fmt.charAt(xPos)))
|
{
|
break;
|
}
|
}
|
|
if ((xPos > pos) && (xPos < fmt.length()))
|
{
|
if (fmt.charAt(xPos) == '$')
|
{
|
positionalPrecision = true;
|
argumentPositionForPrecision = Integer.parseInt(fmt.substring(pos, xPos));
|
pos = xPos + 1;
|
ret = true;
|
}
|
}
|
|
return ret;
|
}
|
|
boolean isPositionalSpecification()
|
{
|
return positionalSpecification;
|
}
|
|
int getArgumentPosition()
|
{
|
return argumentPosition;
|
}
|
|
boolean isPositionalFieldWidth()
|
{
|
return positionalFieldWidth;
|
}
|
|
int getArgumentPositionForFieldWidth()
|
{
|
return argumentPositionForFieldWidth;
|
}
|
|
boolean isPositionalPrecision()
|
{
|
return positionalPrecision;
|
}
|
|
int getArgumentPositionForPrecision()
|
{
|
return argumentPositionForPrecision;
|
}
|
|
/**
|
* Set flag characters, one of '-+#0 or a space.
|
*/
|
private void setFlagCharacters()
|
{
|
/* '-+ #0 */
|
thousands = false;
|
leftJustify = false;
|
leadingSign = false;
|
leadingSpace = false;
|
alternateForm = false;
|
leadingZeros = false;
|
|
for (; pos < fmt.length(); pos++)
|
{
|
char c = fmt.charAt(pos);
|
|
if (c == '\'')
|
{
|
thousands = true;
|
} else if (c == '-')
|
{
|
leftJustify = true;
|
leadingZeros = false;
|
} else if (c == '+')
|
{
|
leadingSign = true;
|
leadingSpace = false;
|
} else if (c == ' ')
|
{
|
if (!leadingSign)
|
{
|
leadingSpace = true;
|
}
|
} else if (c == '#')
|
{
|
alternateForm = true;
|
} else if (c == '0')
|
{
|
if (!leftJustify)
|
{
|
leadingZeros = true;
|
}
|
} else
|
{
|
break;
|
}
|
}
|
}
|
}
|
}
|