org.jpedal.sun.PrintfFormat Maven / Gradle / Ivy
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/java-pdf-library-support/
*
* (C) Copyright 1997-2013, IDRsolutions and Contributors.
*
* This file is part of JPedal
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* PrintfFormat.java
* ---------------
*/
package org.jpedal.sun;
//
// (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.
//
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
/**
* 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.
*
* 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
*
* - is not escaped protected by a matching % or is not an escape % character,
*
- is not at the end of the format string, and
*
- precedes a sequence of characters that parses as a valid control specification.
*
*
*
* A control specification usually takes the form:
*
*
* % ['-+ #0]* [0..9]* { . [0..9]* }+
* { [hlL] }+ [idfgGoxXeEcs]
*
*
* There are variants of this basic form that are discussed below.
*
*
* The format is composed of zero or more directives defined as follows:
*
* - ordinary characters, which are simply copied to the output stream;
*
- escape sequences, which represent non-graphic characters; and
*
- conversion specifications, each of which results in the fetching of 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 evaluated but are otherwise ignored. In format strings containing the % form of
* conversion specifications, each argument in the argument list is used exactly once.
*
*
* Conversions can be applied to the n
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 %n
$, where n
is a decimal integer giving the position of the
* argument in the argument list.
*
*
* In format strings containing the %n
$ form of conversion specifications, each argument in the argument list is used exactly once.
*
*
* Escape Sequences
*
* The following table lists escape sequences and associated actions on display devices capable of the action.
*
*
* Sequence
* Name
* Description
*
*
* \\
* backlash
* None.
*
*
* \a
* alert
* Attempts to alert the user through audible or visible notification.
*
*
* \b
* backspace
* Moves the printing position to one column before the current position, unless the current position is the start of a line.
*
*
* \f
* form-feed
* Moves the printing position to the initial printing position of the next logical page.
*
*
* \n
* newline
* Moves the printing position to the start of the next line.
*
*
* \r
* carriage-return
* Moves the printing position to the start of the current line.
*
*
* \t
* tab
* Moves the printing position to the next implementation- defined horizontal tab position.
*
*
* \v
* vertical-tab
* Moves the printing position to the start of the next implementation-defined vertical tab position.
*
*
*
* Conversion Specifications
*
* Each conversion specification is introduced by the percent sign character (%). After the character %, the following appear in sequence:
*
*
* Zero or more flags (in any order), which modify the meaning of the conversion specification.
*
*
* 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.
*
*
* 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.
*
*
* 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).
*
*
* An optional l (ell) specifies that a following d, i, o, x, or X conversion character applies to a type long argument.
*
*
* 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.
*
*
* In format strings containing the %n
$ form of a conversion specification, a field width or precision may be indicated by the sequence *
* m
$, 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.
*
*
* The format can contain either numbered argument specifications (that is, %n
$ and *m
$), or unnumbered argument
* specifications (that is % and *), but normally not both. The only exception to this is that %% can be mixed with the %n
$ form. The
* results of mixing numbered and unnumbered argument specifications in a format string are undefined.
*
*
* Flag Characters
*
* The flags and their meanings are:
*
*
* - '
*
- 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.
*
- -
*
- result of the conversion is left-justified within the field. (It will be right-justified if this flag is not specified).
*
- +
*
- 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.)
*
- <space>
*
- 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.
*
- #
*
- 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.
*
- 0
*
- 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.
*
*
* Conversion Characters
*
* 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.
*
*
*
* The conversion characters and their meanings are:
*
*
* - d,i
*
- 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.
*
- o
*
- 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.
*
- x
*
- 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.
*
- X
*
- Behaves the same as the x conversion character except that letters ABCDEF are used instead of abcdef.
*
- f
*
- 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.
*
- e,E
*
- 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.
*
- g,G
*
- 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.
*
- c,C
*
- The integer argument is converted to a char and the result is written.
*
*
- s,S
*
- 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.
*
- %
*
- Write a % character; no argument is converted.
*
*
* If a conversion specification does not match one of the above forms, an IllegalArgumentException is thrown and the instance of PrintfFormat is not
* created.
*
*
* 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.
*
*
* 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.
*
*
* 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.
*
*
* 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.
*
*
* 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.
*
*
* 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:
*
*
* - %c is the same as %C.
*
- %s is the same as %S.
*
- u, p, and n conversion characters.
*
- %ws format.
*
- h modifier applied to an n conversion character.
*
- l (ell) modifier applied to the c, n, or s conversion characters.
*
- ll (ell ell) modifier to d, i, o, u, x, or X conversion characters.
*
- ll (ell ell) modifier to an n conversion character.
*
- c, C, d,i,o,u,x, and X conversion characters apply to Byte, Character, Short, Integer, Long types.
*
- f, e, E, g, and G conversion characters apply to Float and Double types.
*
- s and S conversion characters apply to String types.
*
- All other reference types can be formatted using the s or S conversion characters only.
*
*
* Most of this specification is quoted from the Unix man page for the sprintf utility.
*
*
* @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 class PrintfFormat {
/**
* 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 {
this.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);
this.vFmt.add(sFmt);
}
while (this.cPos != -1 && this.cPos < fmtArg.length()) {
for (ePos = this.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(this.cPos, ePos));
this.vFmt.add(sFmt);
unCS = this.nonControl(fmtArg, ePos);
if (unCS != null) {
sFmt = new ConversionSpecification();
sFmt.setLiteral(unCS);
this.vFmt.add(sFmt);
}
}
}
/**
* Return a substring starting at start
and ending at either the end of the String s
, 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 s
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="";
this.cPos = s.indexOf('%', start);
if (this.cPos == -1) this.cPos = s.length();
return s.substring(start, this.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) {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
int i = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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]);
}
if (cs.isPositionalPrecision()) {
int ipr = cs.getArgumentPositionForPrecision() - 1;
cs.setPrecisionWithArg((Integer) o[ipr]);
}
}
else {
if (cs.isVariableFieldWidth()) {
cs.setFieldWidthWithArg((Integer) o[i]);
i++;
}
if (cs.isVariablePrecision()) {
cs.setPrecisionWithArg((Integer) o[i]);
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() {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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 {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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 {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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 {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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 {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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 {
Iterator e = this.vFmt.iterator();
ConversionSpecification cs = null;
char c = 0;
StringBuilder sb = new StringBuilder();
while (e.hasNext()) {
cs = e.next();
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();
}
/**
*
* 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.
*
* 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
*
* - is not escaped protected by a matching % or is not an escape % character,
*
- is not at the end of the format string, and
*
- precedes a sequence of characters that parses as a valid control string.
*
*
* A control string takes the form:
*
*
* % ['-+ #0]* [0..9]* { . [0..9]* }+
* { [hlL] }+ [idfgGoxXeEcs]
*
*
* 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 {
/**
* 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) == '%') {
this.fmt = fmtArg;
this.pos = 1;
setArgPosition();
setFlagCharacters();
setFieldWidth();
setPrecision();
setOptionalHL();
if (setConversionCharacter()) {
if (this.pos == fmtArg.length()) {
if (this.leadingZeros && this.leftJustify) this.leadingZeros = false;
if (this.precisionSet && this.leadingZeros) {
if (this.conversionCharacter == 'd' || this.conversionCharacter == 'i' || this.conversionCharacter == 'o'
|| this.conversionCharacter == 'x') {
this.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) {
this.fmt = s;
}
/**
* Get the String for this instance. Translate any escape sequences.
*
* @return s the stored String.
*/
String getLiteral() {
return this.fmt;
}
/**
* Get the conversion character that tells what type of control character this instance has.
*
* @return the conversion character.
*/
char getConversionCharacter() {
return this.conversionCharacter;
}
/**
* Check whether the specifier has a variable field width that is going to be set by an argument.
*
* @return true
if the conversion uses an * field width; otherwise false
.
*/
boolean isVariableFieldWidth() {
return this.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) this.leftJustify = true;
this.fieldWidthSet = true;
this.fieldWidth = Math.abs(fw);
}
/**
* Check whether the specifier has a variable precision that is going to be set by an argument.
*
* @return true
if the conversion uses an * precision; otherwise false
.
*/
boolean isVariablePrecision() {
return this.variablePrecision;
}
/**
* Set the precision with an argument. A negative precision will be changed to zero.
*
* @param pr
* the precision.
*/
void setPrecisionWithArg(int pr) {
this.precisionSet = true;
this.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 (this.conversionCharacter) {
case 'd':
case 'i':
if (this.optionalh) s2 = printDFormat((short) s);
else
if (this.optionall) s2 = printDFormat((long) s);
else s2 = printDFormat(s);
break;
case 'x':
case 'X':
if (this.optionalh) s2 = printXFormat((short) s);
else
if (this.optionall) s2 = printXFormat((long) s);
else s2 = printXFormat(s);
break;
case 'o':
if (this.optionalh) s2 = printOFormat((short) s);
else
if (this.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 " + this.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 (this.conversionCharacter) {
case 'd':
case 'i':
if (this.optionalh) s2 = printDFormat((short) s);
else
if (this.optionall) s2 = printDFormat(s);
else s2 = printDFormat((int) s);
break;
case 'x':
case 'X':
if (this.optionalh) s2 = printXFormat((short) s);
else
if (this.optionall) s2 = printXFormat(s);
else s2 = printXFormat((int) s);
break;
case 'o':
if (this.optionalh) s2 = printOFormat((short) s);
else
if (this.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 " + this.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 (this.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 " + this.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 (this.conversionCharacter == 's' || this.conversionCharacter == 'S') s2 = printSFormat(s);
else throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + this.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 (this.conversionCharacter == 's' || this.conversionCharacter == 'S') s2 = printSFormat(s.toString());
else throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + this.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 (this.precisionSet) p = this.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 (this.alternateForm || !this.precisionSet || this.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 (this.alternateForm || !this.precisionSet || this.precision != 0) ca4 = new char[n1In + expon + p + 1];
else ca4 = new char[n1In + expon];
j = 0;
}
else {
if (this.alternateForm || !this.precisionSet || this.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 (this.alternateForm || !this.precisionSet || this.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 (!this.leftJustify && this.leadingZeros) {
int xThousands = 0;
if (this.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 (this.fieldWidthSet) nZeros = this.fieldWidth - ca4.length;
if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) nZeros--;
nZeros -= xThousands;
if (nZeros < 0) nZeros = 0;
}
j = 0;
if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) {
ca5 = new char[ca4.length + nZeros + 1];
j++;
}
else ca5 = new char[ca4.length + nZeros];
if (!minusSign) {
if (this.leadingSign) ca5[0] = '+';
if (this.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] = PrintfFormat.this.dfs.getDecimalSeparator();
char[] ca6 = ca5;
if (this.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] = PrintfFormat.this.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 (this.leadingSign) ca6 = "+Inf".toCharArray();
else
if (this.leadingSpace) ca6 = " Inf".toCharArray();
else ca6 = "Inf".toCharArray();
}
else ca6 = "-Inf".toCharArray();
// noDigits = true;
}
else
if (Double.isNaN(x)) {
if (this.leadingSign) ca6 = "+NaN".toCharArray();
else
if (this.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 (this.precisionSet) p = this.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 && !this.optionalL) eSize = 4;
else eSize = 5;
if (this.alternateForm || !this.precisionSet || this.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 (this.alternateForm || !this.precisionSet || this.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 (!this.leftJustify && this.leadingZeros) {
int xThousands = 0;
if (this.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 (this.fieldWidthSet) nZeros = this.fieldWidth - ca2.length;
if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) nZeros--;
nZeros -= xThousands;
if (nZeros < 0) nZeros = 0;
}
j = 0;
if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) {
ca3 = new char[ca2.length + nZeros + 1];
j++;
}
else ca3 = new char[ca2.length + nZeros];
if (!minusSign) {
if (this.leadingSign) ca3[0] = '+';
if (this.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] = PrintfFormat.this.dfs.getDecimalSeparator();
char[] ca4 = ca3;
if (this.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] = PrintfFormat.this.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 true
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 true
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 (this.leadingSign) ca4 = "+Inf".toCharArray();
else
if (this.leadingSpace) ca4 = " Inf".toCharArray();
else ca4 = "Inf".toCharArray();
}
else ca4 = "-Inf".toCharArray();
// noDigits = true;
}
else
if (Double.isNaN(x)) {
if (this.leadingSign) ca4 = "+NaN".toCharArray();
else
if (this.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 (this.fieldWidthSet) {
int i, j, nBlanks;
if (this.leftJustify) {
nBlanks = this.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 (!this.leadingZeros || noDigits) {
nBlanks = this.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 (this.leadingZeros) {
nBlanks = this.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 (this.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 = this.precision;
int i;
char[] ca4, ca5;
// boolean noDigits=false;
if (Double.isInfinite(x)) {
if (x == Double.POSITIVE_INFINITY) {
if (this.leadingSign) ca4 = "+Inf".toCharArray();
else
if (this.leadingSpace) ca4 = " Inf".toCharArray();
else ca4 = "Inf".toCharArray();
}
else ca4 = "-Inf".toCharArray();
// noDigits = true;
}
else
if (Double.isNaN(x)) {
if (this.leadingSign) ca4 = "+NaN".toCharArray();
else
if (this.leadingSpace) ca4 = " NaN".toCharArray();
else ca4 = "NaN".toCharArray();
// noDigits = true;
}
else {
if (!this.precisionSet) this.precision = defaultDigits;
if (this.precision == 0) this.precision = 1;
int ePos = -1;
if (this.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 (!this.alternateForm) {
if (expon >= -4 && expon < this.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 < this.precision) ret = sz;
else ret = sz + sx.substring(ePos);
}
else {
if (expon >= -4 && expon < this.precision) ret = fFormatString(x).trim();
else ret = sx;
}
// leading space was trimmed off during
// construction
if (this.leadingSpace) if (x >= 0) ret = ' ' + ret;
ca4 = ret.toCharArray();
}
// Pad with blanks or zeros.
ca5 = applyFloatPadding(ca4, false);
this.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") && this.precisionSet && this.precision == 0) sx = "";
if (!neg) {
if (this.precisionSet && sx.length() < this.precision) nLeadingZeros = this.precision - sx.length();
}
else {
if (this.precisionSet && (sx.length() - 1) < this.precision) nLeadingZeros = this.precision - sx.length() + 1;
}
if (nLeadingZeros < 0) nLeadingZeros = 0;
if (this.fieldWidthSet) {
nBlanks = this.fieldWidth - nLeadingZeros - sx.length();
if (!neg && (this.leadingSign || this.leadingSpace)) nBlanks--;
}
if (nBlanks < 0) nBlanks = 0;
if (this.leadingSign) n++;
else
if (this.leadingSpace) n++;
n += nBlanks;
n += nLeadingZeros;
n += sx.length();
char[] ca = new char[n];
if (this.leftJustify) {
if (neg) ca[i++] = '-';
else
if (this.leadingSign) ca[i++] = '+';
else
if (this.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 (!this.leadingZeros) {
for (i = 0; i < nBlanks; i++)
ca[i] = ' ';
if (neg) ca[i++] = '-';
else
if (this.leadingSign) ca[i++] = '+';
else
if (this.leadingSpace) ca[i++] = ' ';
}
else {
if (neg) ca[i++] = '-';
else
if (this.leadingSign) ca[i++] = '+';
else
if (this.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(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") && this.precisionSet && this.precision == 0) sx = "";
if (this.precisionSet) nLeadingZeros = this.precision - sx.length();
if (nLeadingZeros < 0) nLeadingZeros = 0;
if (this.fieldWidthSet) {
nBlanks = this.fieldWidth - nLeadingZeros - sx.length();
if (this.alternateForm) nBlanks = nBlanks - 2;
}
if (nBlanks < 0) nBlanks = 0;
int n = 0;
if (this.alternateForm) n += 2;
n += nLeadingZeros;
n += sx.length();
n += nBlanks;
char[] ca = new char[n];
int i = 0;
if (this.leftJustify) {
if (this.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 (!this.leadingZeros) for (int j = 0; j < nBlanks; j++, i++)
ca[i] = ' ';
if (this.alternateForm) {
ca[i++] = '0';
ca[i++] = 'x';
}
if (this.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 (this.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(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") && this.precisionSet && this.precision == 0) sx = "";
if (this.precisionSet) nLeadingZeros = this.precision - sx.length();
if (this.alternateForm) nLeadingZeros++;
if (nLeadingZeros < 0) nLeadingZeros = 0;
if (this.fieldWidthSet) nBlanks = this.fieldWidth - nLeadingZeros - sx.length();
if (nBlanks < 0) nBlanks = 0;
int n = nLeadingZeros + sx.length() + nBlanks;
char[] ca = new char[n];
int i;
if (this.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 (this.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 = this.fieldWidth;
if (!this.fieldWidthSet) width = nPrint;
char[] ca = new char[width];
int i = 0;
if (this.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 = this.fieldWidth;
if (this.precisionSet && nPrint > this.precision) nPrint = this.precision;
if (!this.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 (this.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 true
if the conversion character is there, and false
otherwise.
*/
private boolean setConversionCharacter() {
/* idfgGoxXeEcs */
boolean ret = false;
this.conversionCharacter = '\0';
if (this.pos < this.fmt.length()) {
char c = this.fmt.charAt(this.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 == '%') {
this.conversionCharacter = c;
this.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() {
this.optionalh = false;
this.optionall = false;
this.optionalL = false;
if (this.pos < this.fmt.length()) {
char c = this.fmt.charAt(this.pos);
if (c == 'h') {
this.optionalh = true;
this.pos++;
}
else
if (c == 'l') {
this.optionall = true;
this.pos++;
}
else
if (c == 'L') {
this.optionalL = true;
this.pos++;
}
}
}
/**
* Set the precision.
*/
private void setPrecision() {
int firstPos = this.pos;
this.precisionSet = false;
if (this.pos < this.fmt.length() && this.fmt.charAt(this.pos) == '.') {
this.pos++;
if ((this.pos < this.fmt.length()) && (this.fmt.charAt(this.pos) == '*')) {
this.pos++;
if (!setPrecisionArgPosition()) {
this.variablePrecision = true;
this.precisionSet = true;
}
return;
}
else {
while (this.pos < this.fmt.length()) {
char c = this.fmt.charAt(this.pos);
if (Character.isDigit(c)) this.pos++;
else break;
}
if (this.pos > firstPos + 1) {
String sz = this.fmt.substring(firstPos + 1, this.pos);
this.precision = Integer.parseInt(sz);
this.precisionSet = true;
}
}
}
}
/**
* Set the field width.
*/
private void setFieldWidth() {
int firstPos = this.pos;
this.fieldWidth = 0;
this.fieldWidthSet = false;
if ((this.pos < this.fmt.length()) && (this.fmt.charAt(this.pos) == '*')) {
this.pos++;
if (!setFieldWidthArgPosition()) {
this.variableFieldWidth = true;
this.fieldWidthSet = true;
}
}
else {
while (this.pos < this.fmt.length()) {
char c = this.fmt.charAt(this.pos);
if (Character.isDigit(c)) this.pos++;
else break;
}
if (firstPos < this.pos && firstPos < this.fmt.length()) {
String sz = this.fmt.substring(firstPos, this.pos);
this.fieldWidth = Integer.parseInt(sz);
this.fieldWidthSet = true;
}
}
}
/**
* Store the digits n
in %n$ forms.
*/
private void setArgPosition() {
int xPos;
for (xPos = this.pos; xPos < this.fmt.length(); xPos++) {
if (!Character.isDigit(this.fmt.charAt(xPos))) break;
}
if (xPos > this.pos && xPos < this.fmt.length()) {
if (this.fmt.charAt(xPos) == '$') {
this.positionalSpecification = true;
this.argumentPosition = Integer.parseInt(this.fmt.substring(this.pos, xPos));
this.pos = xPos + 1;
}
}
}
/**
* Store the digits n
in *n$ forms.
*/
private boolean setFieldWidthArgPosition() {
boolean ret = false;
int xPos;
for (xPos = this.pos; xPos < this.fmt.length(); xPos++) {
if (!Character.isDigit(this.fmt.charAt(xPos))) break;
}
if (xPos > this.pos && xPos < this.fmt.length()) {
if (this.fmt.charAt(xPos) == '$') {
this.positionalFieldWidth = true;
this.argumentPositionForFieldWidth = Integer.parseInt(this.fmt.substring(this.pos, xPos));
this.pos = xPos + 1;
ret = true;
}
}
return ret;
}
/**
* Store the digits n
in *n$ forms.
*/
private boolean setPrecisionArgPosition() {
boolean ret = false;
int xPos;
for (xPos = this.pos; xPos < this.fmt.length(); xPos++) {
if (!Character.isDigit(this.fmt.charAt(xPos))) break;
}
if (xPos > this.pos && xPos < this.fmt.length()) {
if (this.fmt.charAt(xPos) == '$') {
this.positionalPrecision = true;
this.argumentPositionForPrecision = Integer.parseInt(this.fmt.substring(this.pos, xPos));
this.pos = xPos + 1;
ret = true;
}
}
return ret;
}
boolean isPositionalSpecification() {
return this.positionalSpecification;
}
int getArgumentPosition() {
return this.argumentPosition;
}
boolean isPositionalFieldWidth() {
return this.positionalFieldWidth;
}
int getArgumentPositionForFieldWidth() {
return this.argumentPositionForFieldWidth;
}
boolean isPositionalPrecision() {
return this.positionalPrecision;
}
int getArgumentPositionForPrecision() {
return this.argumentPositionForPrecision;
}
/**
* Set flag characters, one of '-+#0 or a space.
*/
private void setFlagCharacters() {
/* '-+ #0 */
this.thousands = false;
this.leftJustify = false;
this.leadingSign = false;
this.leadingSpace = false;
this.alternateForm = false;
this.leadingZeros = false;
for (; this.pos < this.fmt.length(); this.pos++) {
char c = this.fmt.charAt(this.pos);
if (c == '\'') this.thousands = true;
else
if (c == '-') {
this.leftJustify = true;
this.leadingZeros = false;
}
else
if (c == '+') {
this.leadingSign = true;
this.leadingSpace = false;
}
else
if (c == ' ') {
if (!this.leadingSign) this.leadingSpace = true;
}
else
if (c == '#') this.alternateForm = true;
else
if (c == '0') {
if (!this.leftJustify) this.leadingZeros = true;
}
else break;
}
}
/**
* 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;
/** Default precision. */
private final static int defaultDigits = 6;
/**
* 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;
}
/** Vector of control strings and format literals. */
private ArrayList vFmt = new ArrayList();
/** Character position. Used by the constructor. */
private int cPos = 0;
/** Character position. Used by the constructor. */
private DecimalFormatSymbols dfs = null;
}