Data Type Java

//package org.swfparser.util;
//
// (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.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.
 * 


 * 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
 * 


     * 
  1. is not escaped protected by a matching % or is not an escape % character,
     * 
  2. is not at the end of the format string, and
     * 
  3. 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 nth 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
 * 

 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
\\backlashNone.
\aalertAttempts to alert the user through audible or visible notification.
\bbackspaceMoves the printing position to one column before the current position,
 * unless the current position is the start of a line.
\fform-feedMoves the printing position to the initial printing position of the next
 * logical page.
\nnewlineMoves the printing position to the start of the next line.
\rcarriage-returnMoves the printing position to the start of the current line.
\ttabMoves the printing position to the next implementation- defined
 * horizontal tab position.
\vvertical-tabMoves 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 {
    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 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 = "";
    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();
  }
  /**
   * 


   * 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
   * 


       * 
  1. is not escaped protected by a matching % or is not an escape %
       * character,
       * 
  2. is not at the end of the format string, and
       * 
  3. 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) == '%') {
        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 true if the conversion uses an * field width;
     *         otherwise false.
     */
    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 true if the conversion uses an * precision;
     *         otherwise false.
     */
    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 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 (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.
     * 
     * @param x
     *            the String to format.
     * @return true if the conversion character is there, and
     *         false 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 n 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 n 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 n 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;
      }
    }
    /**
     * 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 Vector vFmt = new Vector();
  /** Character position. Used by the constructor. */
  private int cPos = 0;
  /** Character position. Used by the constructor. */
  private DecimalFormatSymbols dfs = null;
}