PrintfFormat allows the formatting of an array of objects embedded within a string. : Number Format « Data Type « Java






PrintfFormat allows the formatting of an array of objects embedded within a string.

       
//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.
 * <p>
 * A control string is a Java string that contains a control specification. The
 * control specification starts at the first percent sign (%) in the string,
 * provided that this percent sign
 * <ol>
 * <li>is not escaped protected by a matching % or is not an escape % character,
 * <li>is not at the end of the format string, and
 * <li>precedes a sequence of characters that parses as a valid control
 * specification.
 * </ol>
 * </p>
 * <p>
 * A control specification usually takes the form:
 * 
 * <pre>
 * % ['-+ #0]* [0..9]* { . [0..9]* }+
 *                { [hlL] }+ [idfgGoxXeEcs]
 * </pre>
 * 
 * There are variants of this basic form that are discussed below.
 * </p>
 * <p>
 * The format is composed of zero or more directives defined as follows:
 * <ul>
 * <li>ordinary characters, which are simply copied to the output stream;
 * <li>escape sequences, which represent non-graphic characters; and
 * <li>conversion specifications, each of which results in the fetching of zero
 * or more arguments.
 * </ul>
 * </p>
 * <p>
 * The results are undefined if there are insufficient arguments for the format.
 * Usually an unchecked exception will be thrown. If the format is exhausted
 * while arguments remain, the excess arguments are evaluated but are otherwise
 * ignored. In format strings containing the % form of conversion
 * specifications, each argument in the argument list is used exactly once.
 * </p>
 * <p>
 * Conversions can be applied to the <code>n</code>th argument after the format
 * in the argument list, rather than to the next unused argument. In this case,
 * the conversion characer % is replaced by the sequence %<code>n</code>$, where
 * <code>n</code> is a decimal integer giving the position of the argument in
 * the argument list.
 * </p>
 * <p>
 * In format strings containing the %<code>n</code>$ form of conversion
 * specifications, each argument in the argument list is used exactly once.
 * </p>
 * 
 * <h4>Escape Sequences</h4>
 * <p>
 * The following table lists escape sequences and associated actions on display
 * devices capable of the action.
 * <table>
 * <tr>
 * <th align=left>Sequence</th>
 * <th align=left>Name</th>
 * <th align=left>Description</th>
 * </tr>
 * <tr>
 * <td>\\</td>
 * <td>backlash</td>
 * <td>None.</td>
 * </tr>
 * <tr>
 * <td>\a</td>
 * <td>alert</td>
 * <td>Attempts to alert the user through audible or visible notification.</td>
 * </tr>
 * <tr>
 * <td>\b</td>
 * <td>backspace</td>
 * <td>Moves the printing position to one column before the current position,
 * unless the current position is the start of a line.</td>
 * </tr>
 * <tr>
 * <td>\f</td>
 * <td>form-feed</td>
 * <td>Moves the printing position to the initial printing position of the next
 * logical page.</td>
 * </tr>
 * <tr>
 * <td>\n</td>
 * <td>newline</td>
 * <td>Moves the printing position to the start of the next line.</td>
 * </tr>
 * <tr>
 * <td>\r</td>
 * <td>carriage-return</td>
 * <td>Moves the printing position to the start of the current line.</td>
 * </tr>
 * <tr>
 * <td>\t</td>
 * <td>tab</td>
 * <td>Moves the printing position to the next implementation- defined
 * horizontal tab position.</td>
 * </tr>
 * <tr>
 * <td>\v</td>
 * <td>vertical-tab</td>
 * <td>Moves the printing position to the start of the next
 * implementation-defined vertical tab position.</td>
 * </tr>
 * </table>
 * </p>
 * <h4>Conversion Specifications</h4>
 * <p>
 * Each conversion specification is introduced by the percent sign character
 * (%). After the character %, the following appear in sequence:
 * </p>
 * <p>
 * Zero or more flags (in any order), which modify the meaning of the conversion
 * specification.
 * </p>
 * <p>
 * An optional minimum field width. If the converted value has fewer characters
 * than the field width, it will be padded with spaces by default on the left; t
 * will be padded on the right, if the left- adjustment flag (-), described
 * below, is given to the field width. The field width takes the form of a
 * decimal integer. If the conversion character is s, the field width is the the
 * minimum number of characters to be printed.
 * </p>
 * <p>
 * An optional precision that gives the minumum number of digits to appear for
 * the d, i, o, x or X conversions (the field is padded with leading zeros); the
 * number of digits to appear after the radix character for the e, E, and f
 * conversions, the maximum number of significant digits for the g and G
 * conversions; or the maximum number of characters to be written from a string
 * is s and S conversions. The precision takes the form of an optional decimal
 * digit string, where a null digit string is treated as 0. If a precision
 * appears with a c conversion character the precision is ignored.
 * </p>
 * <p>
 * An optional h specifies that a following d, i, o, x, or X conversion
 * character applies to a type short argument (the argument will be promoted
 * according to the integral promotions and its value converted to type short
 * before printing).
 * </p>
 * <p>
 * An optional l (ell) specifies that a following d, i, o, x, or X conversion
 * character applies to a type long argument.
 * </p>
 * <p>
 * A field width or precision may be indicated by an asterisk (*) instead of a
 * digit string. In this case, an integer argument supplised the field width
 * precision. The argument that is actually converted is not fetched until the
 * conversion letter is seen, so the the arguments specifying field width or
 * precision must appear before the argument (if any) to be converted. If the
 * precision argument is negative, it will be changed to zero. A negative field
 * width argument is taken as a - flag, followed by a positive field width.
 * </p>
 * <p>
 * In format strings containing the %<code>n</code>$ form of a conversion
 * specification, a field width or precision may be indicated by the sequence *
 * <code>m</code>$, where m is a decimal integer giving the position in the
 * argument list (after the format argument) of an integer argument containing
 * the field width or precision.
 * </p>
 * <p>
 * The format can contain either numbered argument specifications (that is, %
 * <code>n</code>$ and *<code>m</code>$), or unnumbered argument specifications
 * (that is % and *), but normally not both. The only exception to this is that
 * %% can be mixed with the %<code>n</code>$ form. The results of mixing
 * numbered and unnumbered argument specifications in a format string are
 * undefined.
 * </p>
 * 
 * <h4>Flag Characters</h4>
 * <p>
 * The flags and their meanings are:
 * </p>
 * <dl>
 * <dt>'
 * <dd>integer portion of the result of a decimal conversion (%i, %d, %f, %g, or
 * %G) will be formatted with thousands' grouping characters. For other
 * conversions the flag is ignored. The non-monetary grouping character is used.
 * <dt>-
 * <dd>result of the conversion is left-justified within the field. (It will be
 * right-justified if this flag is not specified).</td></tr>
 * <dt>+
 * <dd>result of a signed conversion always begins with a sign (+ or -). (It
 * will begin with a sign only when a negative value is converted if this flag
 * is not specified.)
 * <dt>&lt;space&gt;
 * <dd>If the first character of a signed conversion is not a sign, a space
 * character will be placed before the result. This means that if the space
 * character and + flags both appear, the space flag will be ignored.
 * <dt>#
 * <dd>value is to be converted to an alternative form. For c, d, i, and s
 * conversions, the flag has no effect. For o conversion, it increases the
 * precision to force the first digit of the result to be a zero. For x or X
 * conversion, a non-zero result has 0x or 0X prefixed to it, respectively. For
 * e, E, f, g, and G conversions, the result always contains a radix character,
 * even if no digits follow the radix character (normally, a decimal point
 * appears in the result of these conversions only if a digit follows it). For g
 * and G conversions, trailing zeros will not be removed from the result as they
 * normally are.
 * <dt>0
 * <dd>d, i, o, x, X, e, E, f, g, and G conversions, leading zeros (following
 * any indication of sign or base) are used to pad to the field width; no space
 * padding is performed. If the 0 and - flags both appear, the 0 flag is
 * ignored. For d, i, o, x, and X conversions, if a precision is specified, the
 * 0 flag will be ignored. For c conversions, the flag is ignored.
 * </dl>
 * 
 * <h4>Conversion Characters</h4>
 * <p>
 * Each conversion character results in fetching zero or more arguments. The
 * results are undefined if there are insufficient arguments for the format.
 * Usually, an unchecked exception will be thrown. If the format is exhausted
 * while arguments remain, the excess arguments are ignored.
 * </p>
 * 
 * <p>
 * The conversion characters and their meanings are:
 * </p>
 * <dl>
 * <dt>d,i
 * <dd>The int argument is converted to a signed decimal in the style [-]dddd.
 * The precision specifies the minimum number of digits to appear; if the value
 * being converted can be represented in fewer digits, it will be expanded with
 * leading zeros. The default precision is 1. The result of converting 0 with an
 * explicit precision of 0 is no characters.
 * <dt>o
 * <dd>The int argument is converted to unsigned octal format in the style
 * ddddd. The precision specifies the minimum number of digits to appear; if the
 * value being converted can be represented in fewer digits, it will be expanded
 * with leading zeros. The default precision is 1. The result of converting 0
 * with an explicit precision of 0 is no characters.
 * <dt>x
 * <dd>The int argument is converted to unsigned hexadecimal format in the style
 * dddd; the letters abcdef are used. The precision specifies the minimum
 * numberof digits to appear; if the value being converted can be represented in
 * fewer digits, it will be expanded with leading zeros. The default precision
 * is 1. The result of converting 0 with an explicit precision of 0 is no
 * characters.
 * <dt>X
 * <dd>Behaves the same as the x conversion character except that letters ABCDEF
 * are used instead of abcdef.
 * <dt>f
 * <dd>The floating point number argument is written in decimal notation in the
 * style [-]ddd.ddd, where the number of digits after the radix character (shown
 * here as a decimal point) is equal to the precision specification. A Locale is
 * used to determine the radix character to use in this format. If the precision
 * is omitted from the argument, six digits are written after the radix
 * character; if the precision is explicitly 0 and the # flag is not specified,
 * no radix character appears. If a radix character appears, at least 1 digit
 * appears before it. The value is rounded to the appropriate number of digits.
 * <dt>e,E
 * <dd>The floating point number argument is written in the style
 * [-]d.ddde{+-}dd (the symbols {+-} indicate either a plus or minus sign),
 * where there is one digit before the radix character (shown here as a decimal
 * point) and the number of digits after it is equal to the precision. A Locale
 * is used to determine the radix character to use in this format. When the
 * precision is missing, six digits are written after the radix character; if
 * the precision is 0 and the # flag is not specified, no radix character
 * appears. The E conversion will produce a number with E instead of e
 * introducing the exponent. The exponent always contains at least two digits.
 * However, if the value to be written requires an exponent greater than two
 * digits, additional exponent digits are written as necessary. The value is
 * rounded to the appropriate number of digits.
 * <dt>g,G
 * <dd>The floating point number argument is written in style f or e (or in
 * sytle E in the case of a G conversion character), with the precision
 * specifying the number of significant digits. If the precision is zero, it is
 * taken as one. The style used depends on the value converted: style e (or E)
 * will be used only if the exponent resulting from the conversion is less than
 * -4 or greater than or equal to the precision. Trailing zeros are removed from
 * the result. A radix character appears only if it is followed by a digit.
 * <dt>c,C
 * <dd>The integer argument is converted to a char and the result is written.
 * 
 * <dt>s,S
 * <dd>The argument is taken to be a string and bytes from the string are
 * written until the end of the string or the number of bytes indicated by the
 * precision specification of the argument is reached. If the precision is
 * omitted from the argument, it is taken to be infinite, so all characters up
 * to the end of the string are written.
 * <dt>%
 * <dd>Write a % character; no argument is converted.
 * </dl>
 * <p>
 * If a conversion specification does not match one of the above forms, an
 * IllegalArgumentException is thrown and the instance of PrintfFormat is not
 * created.
 * </p>
 * <p>
 * If a floating point value is the internal representation for infinity, the
 * output is [+]Infinity, where Infinity is either Infinity or Inf, depending on
 * the desired output string length. Printing of the sign follows the rules
 * described above.
 * </p>
 * <p>
 * If a floating point value is the internal representation for "not-a-number,"
 * the output is [+]NaN. Printing of the sign follows the rules described above.
 * </p>
 * <p>
 * In no case does a non-existent or small field width cause truncation of a
 * field; if the result of a conversion is wider than the field width, the field
 * is simply expanded to contain the conversion result.
 * </p>
 * <p>
 * The behavior is like printf. One exception is that the minimum number of
 * exponent digits is 3 instead of 2 for e and E formats when the optional L is
 * used before the e, E, g, or G conversion character. The optional L does not
 * imply conversion to a long long double.
 * </p>
 * <p>
 * The biggest divergence from the C printf specification is in the use of 16
 * bit characters. This allows the handling of characters beyond the small ASCII
 * character set and allows the utility to interoperate correctly with the rest
 * of the Java runtime environment.
 * </p>
 * <p>
 * Omissions from the C printf specification are numerous. All the known
 * omissions are present because Java never uses bytes to represent characters
 * and does not have pointers:
 * </p>
 * <ul>
 * <li>%c is the same as %C.
 * <li>%s is the same as %S.
 * <li>u, p, and n conversion characters.
 * <li>%ws format.
 * <li>h modifier applied to an n conversion character.
 * <li>l (ell) modifier applied to the c, n, or s conversion characters.
 * <li>ll (ell ell) modifier to d, i, o, u, x, or X conversion characters.
 * <li>ll (ell ell) modifier to an n conversion character.
 * <li>c, C, d,i,o,u,x, and X conversion characters apply to Byte, Character,
 * Short, Integer, Long types.
 * <li>f, e, E, g, and G conversion characters apply to Float and Double types.
 * <li>s and S conversion characters apply to String types.
 * <li>All other reference types can be formatted using the s or S conversion
 * characters only.
 * </ul>
 * <p>
 * Most of this specification is quoted from the Unix man page for the sprintf
 * utility.
 * </p>
 * 
 * @author Allan Jacobs
 * @version 1 Release 1: Initial release. Release 2: Asterisk field widths and
 *          precisions %n$ and *m$ Bug fixes g format fix (2 digits in e form
 *          corrupt) rounding in f format implemented round up when digit not
 *          printed is 5 formatting of -0.0f round up/down when last digits are
 *          50000...
 */
public 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 <code>start</code> and ending at either
   * the end of the String <code>s</code>, the next unpaired percent sign, or
   * at the end of the String if the last character is a percent sign.
   * 
   * @param s
   *            Control string.
   * @param start
   *            Position in the string <code>s</code> to begin looking for the
   *            start of a control string.
   * @return the substring from the start position to the beginning of the
   *         control string.
   */
  private String nonControl(String s, int start) {
    String ret = "";
    cPos = s.indexOf("%", start);
    if (cPos == -1)
      cPos = s.length();
    return s.substring(start, cPos);
  }

  /**
   * Format an array of objects. Byte, Short, Integer, Long, Float, Double,
   * and Character arguments are treated as wrappers for primitive types.
   * 
   * @param o
   *            The array of objects to format.
   * @return The formatted String.
   */
  public String sprintf(Object[] o) {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    int i = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
      else {
        if (cs.isPositionalSpecification()) {
          i = cs.getArgumentPosition() - 1;
          if (cs.isPositionalFieldWidth()) {
            int ifw = cs.getArgumentPositionForFieldWidth() - 1;
            cs.setFieldWidthWithArg(((Integer) o[ifw]).intValue());
          }
          if (cs.isPositionalPrecision()) {
            int ipr = cs.getArgumentPositionForPrecision() - 1;
            cs.setPrecisionWithArg(((Integer) o[ipr]).intValue());
          }
        } else {
          if (cs.isVariableFieldWidth()) {
            cs.setFieldWidthWithArg(((Integer) o[i]).intValue());
            i++;
          }
          if (cs.isVariablePrecision()) {
            cs.setPrecisionWithArg(((Integer) o[i]).intValue());
            i++;
          }
        }
        if (o[i] instanceof Byte)
          sb.append(cs.internalsprintf(((Byte) o[i]).byteValue()));
        else if (o[i] instanceof Short)
          sb.append(cs.internalsprintf(((Short) o[i]).shortValue()));
        else if (o[i] instanceof Integer)
          sb.append(cs.internalsprintf(((Integer) o[i]).intValue()));
        else if (o[i] instanceof Long)
          sb.append(cs.internalsprintf(((Long) o[i]).longValue()));
        else if (o[i] instanceof Float)
          sb.append(cs.internalsprintf(((Float) o[i]).floatValue()));
        else if (o[i] instanceof Double)
          sb.append(cs.internalsprintf(((Double) o[i]).doubleValue()));
        else if (o[i] instanceof Character)
          sb.append(cs.internalsprintf(((Character) o[i]).charValue()));
        else if (o[i] instanceof String)
          sb.append(cs.internalsprintf((String) o[i]));
        else
          sb.append(cs.internalsprintf(o[i]));
        if (!cs.isPositionalSpecification())
          i++;
      }
    }
    return sb.toString();
  }

  /**
   * Format nothing. Just use the control string.
   * 
   * @return the formatted String.
   */
  public String sprintf() {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
    }
    return sb.toString();
  }

  /**
   * Format an int.
   * 
   * @param x
   *            The int to format.
   * @return The formatted String.
   * @exception IllegalArgumentException
   *                if the conversion character is f, e, E, g, G, s, or S.
   */
  public String sprintf(int x) throws IllegalArgumentException {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
      else
        sb.append(cs.internalsprintf(x));
    }
    return sb.toString();
  }

  /**
   * Format an long.
   * 
   * @param x
   *            The long to format.
   * @return The formatted String.
   * @exception IllegalArgumentException
   *                if the conversion character is f, e, E, g, G, s, or S.
   */
  public String sprintf(long x) throws IllegalArgumentException {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
      else
        sb.append(cs.internalsprintf(x));
    }
    return sb.toString();
  }

  /**
   * Format a double.
   * 
   * @param x
   *            The double to format.
   * @return The formatted String.
   * @exception IllegalArgumentException
   *                if the conversion character is c, C, s, S, d, d, x, X, or
   *                o.
   */
  public String sprintf(double x) throws IllegalArgumentException {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
      else
        sb.append(cs.internalsprintf(x));
    }
    return sb.toString();
  }

  /**
   * Format a String.
   * 
   * @param x
   *            The String to format.
   * @return The formatted String.
   * @exception IllegalArgumentException
   *                if the conversion character is neither s nor S.
   */
  public String sprintf(String x) throws IllegalArgumentException {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
      else
        sb.append(cs.internalsprintf(x));
    }
    return sb.toString();
  }

  /**
   * Format an Object. Convert wrapper types to their primitive equivalents
   * and call the appropriate internal formatting method. Convert Strings
   * using an internal formatting method for Strings. Otherwise use the
   * default formatter (use toString).
   * 
   * @param x
   *            the Object to format.
   * @return the formatted String.
   * @exception IllegalArgumentException
   *                if the conversion character is inappropriate for
   *                formatting an unwrapped value.
   */
  public String sprintf(Object x) throws IllegalArgumentException {
    Enumeration e = vFmt.elements();
    ConversionSpecification cs = null;
    char c = 0;
    StringBuffer sb = new StringBuffer();
    while (e.hasMoreElements()) {
      cs = (ConversionSpecification) e.nextElement();
      c = cs.getConversionCharacter();
      if (c == '\0')
        sb.append(cs.getLiteral());
      else if (c == '%')
        sb.append("%");
      else {
        if (x instanceof Byte)
          sb.append(cs.internalsprintf(((Byte) x).byteValue()));
        else if (x instanceof Short)
          sb.append(cs.internalsprintf(((Short) x).shortValue()));
        else if (x instanceof Integer)
          sb.append(cs.internalsprintf(((Integer) x).intValue()));
        else if (x instanceof Long)
          sb.append(cs.internalsprintf(((Long) x).longValue()));
        else if (x instanceof Float)
          sb.append(cs.internalsprintf(((Float) x).floatValue()));
        else if (x instanceof Double)
          sb.append(cs.internalsprintf(((Double) x).doubleValue()));
        else if (x instanceof Character)
          sb.append(cs.internalsprintf(((Character) x).charValue()));
        else if (x instanceof String)
          sb.append(cs.internalsprintf((String) x));
        else
          sb.append(cs.internalsprintf(x));
      }
    }
    return sb.toString();
  }

  /**
   * <p>
   * ConversionSpecification allows the formatting of a single primitive or
   * object embedded within a string. The formatting is controlled by a format
   * string. Only one Java primitive or object can be formatted at a time.
   * <p>
   * A format string is a Java string that contains a control string. The
   * control string starts at the first percent sign (%) in the string,
   * provided that this percent sign
   * <ol>
   * <li>is not escaped protected by a matching % or is not an escape %
   * character,
   * <li>is not at the end of the format string, and
   * <li>precedes a sequence of characters that parses as a valid control
   * string.
   * </ol>
   * <p>
   * A control string takes the form:
   * 
   * <pre>
   * % ['-+ #0]* [0..9]* { . [0..9]* }+
   *                { [hlL] }+ [idfgGoxXeEcs]
   * </pre>
   * <p>
   * The behavior is like printf. One (hopefully the only) exception is that
   * the minimum number of exponent digits is 3 instead of 2 for e and E
   * formats when the optional L is used before the e, E, g, or G conversion
   * character. The optional L does not imply conversion to a long long
   * double.
   */
  private class ConversionSpecification {
    /**
     * Constructor. Used to prepare an instance to hold a literal, not a
     * control string.
     */
    ConversionSpecification() {
    }

    /**
     * Constructor for a conversion specification. The argument must begin
     * with a % and end with the conversion character for the conversion
     * specification.
     * 
     * @param fmtArg
     *            String specifying the conversion specification.
     * @exception IllegalArgumentException
     *                if the input string is null, zero length, or otherwise
     *                malformed.
     */
    ConversionSpecification(String fmtArg) throws IllegalArgumentException {
      if (fmtArg == null)
        throw new NullPointerException();
      if (fmtArg.length() == 0)
        throw new IllegalArgumentException(
            "Control strings must have positive" + " lengths.");
      if (fmtArg.charAt(0) == '%') {
        fmt = fmtArg;
        pos = 1;
        setArgPosition();
        setFlagCharacters();
        setFieldWidth();
        setPrecision();
        setOptionalHL();
        if (setConversionCharacter()) {
          if (pos == fmtArg.length()) {
            if (leadingZeros && leftJustify)
              leadingZeros = false;
            if (precisionSet && leadingZeros) {
              if (conversionCharacter == 'd'
                  || conversionCharacter == 'i'
                  || conversionCharacter == 'o'
                  || conversionCharacter == 'x') {
                leadingZeros = false;
              }
            }
          } else
            throw new IllegalArgumentException(
                "Malformed conversion specification=" + fmtArg);
        } else
          throw new IllegalArgumentException(
              "Malformed conversion specification=" + fmtArg);
      } else
        throw new IllegalArgumentException(
            "Control strings must begin with %.");
    }

    /**
     * Set the String for this instance.
     * 
     * @param s
     *            the String to store.
     */
    void setLiteral(String s) {
      fmt = s;
    }

    /**
     * Get the String for this instance. Translate any escape sequences.
     * 
     * @return s the stored String.
     */
    String getLiteral() {
      StringBuffer sb = new StringBuffer();
      int i = 0;
      while (i < fmt.length()) {
        if (fmt.charAt(i) == '\\') {
          i++;
          if (i < fmt.length()) {
            char c = fmt.charAt(i);
            switch (c) {
            case 'a':
              sb.append((char) 0x07);
              break;
            case 'b':
              sb.append('\b');
              break;
            case 'f':
              sb.append('\f');
              break;
            case 'n':
              sb.append(System.getProperty("line.separator"));
              break;
            case 'r':
              sb.append('\r');
              break;
            case 't':
              sb.append('\t');
              break;
            case 'v':
              sb.append((char) 0x0b);
              break;
            case '\\':
              sb.append('\\');
              break;
            }
            i++;
          } else
            sb.append('\\');
        } else
          i++;
      }
      return fmt;
    }

    /**
     * Get the conversion character that tells what type of control
     * character this instance has.
     * 
     * @return the conversion character.
     */
    char getConversionCharacter() {
      return conversionCharacter;
    }

    /**
     * Check whether the specifier has a variable field width that is going
     * to be set by an argument.
     * 
     * @return <code>true</code> if the conversion uses an * field width;
     *         otherwise <code>false</code>.
     */
    boolean isVariableFieldWidth() {
      return variableFieldWidth;
    }

    /**
     * Set the field width with an argument. A negative field width is taken
     * as a - flag followed by a positive field width.
     * 
     * @param fw
     *            the field width.
     */
    void setFieldWidthWithArg(int fw) {
      if (fw < 0)
        leftJustify = true;
      fieldWidthSet = true;
      fieldWidth = Math.abs(fw);
    }

    /**
     * Check whether the specifier has a variable precision that is going to
     * be set by an argument.
     * 
     * @return <code>true</code> if the conversion uses an * precision;
     *         otherwise <code>false</code>.
     */
    boolean isVariablePrecision() {
      return variablePrecision;
    }

    /**
     * Set the precision with an argument. A negative precision will be
     * changed to zero.
     * 
     * @param pr
     *            the precision.
     */
    void setPrecisionWithArg(int pr) {
      precisionSet = true;
      precision = Math.max(pr, 0);
    }

    /**
     * Format an int argument using this conversion specification.
     * 
     * @param s
     *            the int to format.
     * @return the formatted String.
     * @exception IllegalArgumentException
     *                if the conversion character is f, e, E, g, or G.
     */
    String internalsprintf(int s) throws IllegalArgumentException {
      String s2 = "";
      switch (conversionCharacter) {
      case 'd':
      case 'i':
        if (optionalh)
          s2 = printDFormat((short) s);
        else if (optionall)
          s2 = printDFormat((long) s);
        else
          s2 = printDFormat(s);
        break;
      case 'x':
      case 'X':
        if (optionalh)
          s2 = printXFormat((short) s);
        else if (optionall)
          s2 = printXFormat((long) s);
        else
          s2 = printXFormat(s);
        break;
      case 'o':
        if (optionalh)
          s2 = printOFormat((short) s);
        else if (optionall)
          s2 = printOFormat((long) s);
        else
          s2 = printOFormat(s);
        break;
      case 'c':
      case 'C':
        s2 = printCFormat((char) s);
        break;
      default:
        throw new IllegalArgumentException(
            "Cannot format a int with a format using a "
                + conversionCharacter
                + " conversion character.");
      }
      return s2;
    }

    /**
     * Format a long argument using this conversion specification.
     * 
     * @param s
     *            the long to format.
     * @return the formatted String.
     * @exception IllegalArgumentException
     *                if the conversion character is f, e, E, g, or G.
     */
    String internalsprintf(long s) throws IllegalArgumentException {
      String s2 = "";
      switch (conversionCharacter) {
      case 'd':
      case 'i':
        if (optionalh)
          s2 = printDFormat((short) s);
        else if (optionall)
          s2 = printDFormat(s);
        else
          s2 = printDFormat((int) s);
        break;
      case 'x':
      case 'X':
        if (optionalh)
          s2 = printXFormat((short) s);
        else if (optionall)
          s2 = printXFormat(s);
        else
          s2 = printXFormat((int) s);
        break;
      case 'o':
        if (optionalh)
          s2 = printOFormat((short) s);
        else if (optionall)
          s2 = printOFormat(s);
        else
          s2 = printOFormat((int) s);
        break;
      case 'c':
      case 'C':
        s2 = printCFormat((char) s);
        break;
      default:
        throw new IllegalArgumentException(
            "Cannot format a long with a format using a "
                + conversionCharacter
                + " conversion character.");
      }
      return s2;
    }

    /**
     * Format a double argument using this conversion specification.
     * 
     * @param s
     *            the double to format.
     * @return the formatted String.
     * @exception IllegalArgumentException
     *                if the conversion character is c, C, s, S, i, d, x, X,
     *                or o.
     */
    String internalsprintf(double s) throws IllegalArgumentException {
      String s2 = "";
      switch (conversionCharacter) {
      case 'f':
        s2 = printFFormat(s);
        break;
      case 'E':
      case 'e':
        s2 = printEFormat(s);
        break;
      case 'G':
      case 'g':
        s2 = printGFormat(s);
        break;
      default:
        throw new IllegalArgumentException("Cannot "
            + "format a double with a format using a "
            + conversionCharacter + " conversion character.");
      }
      return s2;
    }

    /**
     * Format a String argument using this conversion specification.
     * 
     * @param s
     *            the String to format.
     * @return the formatted String.
     * @exception IllegalArgumentException
     *                if the conversion character is neither s nor S.
     */
    String internalsprintf(String s) throws IllegalArgumentException {
      String s2 = "";
      if (conversionCharacter == 's' || conversionCharacter == 'S')
        s2 = printSFormat(s);
      else
        throw new IllegalArgumentException("Cannot "
            + "format a String with a format using a "
            + conversionCharacter + " conversion character.");
      return s2;
    }

    /**
     * Format an Object argument using this conversion specification.
     * 
     * @param s
     *            the Object to format.
     * @return the formatted String.
     * @exception IllegalArgumentException
     *                if the conversion character is neither s nor S.
     */
    String internalsprintf(Object s) {
      String s2 = "";
      if (conversionCharacter == 's' || conversionCharacter == 'S')
        s2 = printSFormat(s.toString());
      else
        throw new IllegalArgumentException(
            "Cannot format a String with a format using" + " a "
                + conversionCharacter
                + " conversion character.");
      return s2;
    }

    /**
     * For f format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. '+' character means that the conversion will always begin
     * with a sign (+ or -). The blank flag character means that a
     * non-negative input will be preceded with a blank. If both a '+' and a
     * ' ' are specified, the blank flag is ignored. The '0' flag character
     * implies that padding to the field width will be done with zeros
     * instead of blanks.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the number of digits to appear after the
     * radix character. Padding is with trailing 0s.
     */
    private char[] fFormatDigits(double x) {
      // int defaultDigits=6;
      String sx, sxOut;
      int i, j, k;
      int n1In, n2In;
      int expon = 0;
      boolean minusSign = false;
      if (x > 0.0)
        sx = Double.toString(x);
      else if (x < 0.0) {
        sx = Double.toString(-x);
        minusSign = true;
      } else {
        sx = Double.toString(x);
        if (sx.charAt(0) == '-') {
          minusSign = true;
          sx = sx.substring(1);
        }
      }
      int ePos = sx.indexOf('E');
      int rPos = sx.indexOf('.');
      if (rPos != -1)
        n1In = rPos;
      else if (ePos != -1)
        n1In = ePos;
      else
        n1In = sx.length();
      if (rPos != -1) {
        if (ePos != -1)
          n2In = ePos - rPos - 1;
        else
          n2In = sx.length() - rPos - 1;
      } else
        n2In = 0;
      if (ePos != -1) {
        int ie = ePos + 1;
        expon = 0;
        if (sx.charAt(ie) == '-') {
          for (++ie; ie < sx.length(); ie++)
            if (sx.charAt(ie) != '0')
              break;
          if (ie < sx.length())
            expon = -Integer.parseInt(sx.substring(ie));
        } else {
          if (sx.charAt(ie) == '+')
            ++ie;
          for (; ie < sx.length(); ie++)
            if (sx.charAt(ie) != '0')
              break;
          if (ie < sx.length())
            expon = Integer.parseInt(sx.substring(ie));
        }
      }
      int p;
      if (precisionSet)
        p = precision;
      else
        p = defaultDigits - 1;
      char[] ca1 = sx.toCharArray();
      char[] ca2 = new char[n1In + n2In];
      char[] ca3, ca4, ca5;
      for (j = 0; j < n1In; j++)
        ca2[j] = ca1[j];
      i = j + 1;
      for (k = 0; k < n2In; j++, i++, k++)
        ca2[j] = ca1[i];
      if (n1In + expon <= 0) {
        ca3 = new char[-expon + n2In];
        for (j = 0, k = 0; k < (-n1In - expon); k++, j++)
          ca3[j] = '0';
        for (i = 0; i < (n1In + n2In); i++, j++)
          ca3[j] = ca2[i];
      } else
        ca3 = ca2;
      boolean carry = false;
      if (p < -expon + n2In) {
        if (expon < 0)
          i = p;
        else
          i = p + n1In;
        carry = checkForCarry(ca3, i);
        if (carry)
          carry = startSymbolicCarry(ca3, i - 1, 0);
      }
      if (n1In + expon <= 0) {
        ca4 = new char[2 + p];
        if (!carry)
          ca4[0] = '0';
        else
          ca4[0] = '1';
        if (alternateForm || !precisionSet || precision != 0) {
          ca4[1] = '.';
          for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
            ca4[j] = ca3[i];
          for (; j < ca4.length; j++)
            ca4[j] = '0';
        }
      } else {
        if (!carry) {
          if (alternateForm || !precisionSet || precision != 0)
            ca4 = new char[n1In + expon + p + 1];
          else
            ca4 = new char[n1In + expon];
          j = 0;
        } else {
          if (alternateForm || !precisionSet || precision != 0)
            ca4 = new char[n1In + expon + p + 2];
          else
            ca4 = new char[n1In + expon + 1];
          ca4[0] = '1';
          j = 1;
        }
        for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
          ca4[j] = ca3[i];
        for (; i < n1In + expon; i++, j++)
          ca4[j] = '0';
        if (alternateForm || !precisionSet || precision != 0) {
          ca4[j] = '.';
          j++;
          for (k = 0; i < ca3.length && k < p; i++, j++, k++)
            ca4[j] = ca3[i];
          for (; j < ca4.length; j++)
            ca4[j] = '0';
        }
      }
      int nZeros = 0;
      if (!leftJustify && leadingZeros) {
        int xThousands = 0;
        if (thousands) {
          int xlead = 0;
          if (ca4[0] == '+' || ca4[0] == '-' || ca4[0] == ' ')
            xlead = 1;
          int xdp = xlead;
          for (; xdp < ca4.length; xdp++)
            if (ca4[xdp] == '.')
              break;
          xThousands = (xdp - xlead) / 3;
        }
        if (fieldWidthSet)
          nZeros = fieldWidth - ca4.length;
        if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
          nZeros--;
        nZeros -= xThousands;
        if (nZeros < 0)
          nZeros = 0;
      }
      j = 0;
      if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) {
        ca5 = new char[ca4.length + nZeros + 1];
        j++;
      } else
        ca5 = new char[ca4.length + nZeros];
      if (!minusSign) {
        if (leadingSign)
          ca5[0] = '+';
        if (leadingSpace)
          ca5[0] = ' ';
      } else
        ca5[0] = '-';
      for (i = 0; i < nZeros; i++, j++)
        ca5[j] = '0';
      for (i = 0; i < ca4.length; i++, j++)
        ca5[j] = ca4[i];

      int lead = 0;
      if (ca5[0] == '+' || ca5[0] == '-' || ca5[0] == ' ')
        lead = 1;
      int dp = lead;
      for (; dp < ca5.length; dp++)
        if (ca5[dp] == '.')
          break;
      int nThousands = (dp - lead) / 3;
      // Localize the decimal point.
      if (dp < ca5.length)
        ca5[dp] = dfs.getDecimalSeparator();
      char[] ca6 = ca5;
      if (thousands && nThousands > 0) {
        ca6 = new char[ca5.length + nThousands + lead];
        ca6[0] = ca5[0];
        for (i = lead, k = lead; i < dp; i++) {
          if (i > 0 && (dp - i) % 3 == 0) {
            // ca6[k]=',';
            ca6[k] = dfs.getGroupingSeparator();
            ca6[k + 1] = ca5[i];
            k += 2;
          } else {
            ca6[k] = ca5[i];
            k++;
          }
        }
        for (; i < ca5.length; i++, k++) {
          ca6[k] = ca5[i];
        }
      }
      return ca6;
    }

    /**
     * An intermediate routine on the way to creating an f format String.
     * The method decides whether the input double value is an infinity,
     * not-a-number, or a finite double and formats each type of input
     * appropriately.
     * 
     * @param x
     *            the double value to be formatted.
     * @return the converted double value.
     */
    private String fFormatString(double x) {
      boolean noDigits = false;
      char[] ca6, ca7;
      if (Double.isInfinite(x)) {
        if (x == Double.POSITIVE_INFINITY) {
          if (leadingSign)
            ca6 = "+Inf".toCharArray();
          else if (leadingSpace)
            ca6 = " Inf".toCharArray();
          else
            ca6 = "Inf".toCharArray();
        } else
          ca6 = "-Inf".toCharArray();
        noDigits = true;
      } else if (Double.isNaN(x)) {
        if (leadingSign)
          ca6 = "+NaN".toCharArray();
        else if (leadingSpace)
          ca6 = " NaN".toCharArray();
        else
          ca6 = "NaN".toCharArray();
        noDigits = true;
      } else
        ca6 = fFormatDigits(x);
      ca7 = applyFloatPadding(ca6, false);
      return new String(ca7);
    }

    /**
     * For e format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. '+' character means that the conversion will always begin
     * with a sign (+ or -). The blank flag character means that a
     * non-negative input will be preceded with a blank. If both a '+' and a
     * ' ' are specified, the blank flag is ignored. The '0' flag character
     * implies that padding to the field width will be done with zeros
     * instead of blanks.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear
     * after the radix character. Padding is with trailing 0s.
     * 
     * The behavior is like printf. One (hopefully the only) exception is
     * that the minimum number of exponent digits is 3 instead of 2 for e
     * and E formats when the optional L is used before the e, E, g, or G
     * conversion character. The optional L does not imply conversion to a
     * long long double.
     */
    private char[] eFormatDigits(double x, char eChar) {
      char[] ca1, ca2, ca3;
      // int defaultDigits=6;
      String sx, sxOut;
      int i, j, k, p;
      int n1In, n2In;
      int expon = 0;
      int ePos, rPos, eSize;
      boolean minusSign = false;
      if (x > 0.0)
        sx = Double.toString(x);
      else if (x < 0.0) {
        sx = Double.toString(-x);
        minusSign = true;
      } else {
        sx = Double.toString(x);
        if (sx.charAt(0) == '-') {
          minusSign = true;
          sx = sx.substring(1);
        }
      }
      ePos = sx.indexOf('E');
      if (ePos == -1)
        ePos = sx.indexOf('e');
      rPos = sx.indexOf('.');
      if (rPos != -1)
        n1In = rPos;
      else if (ePos != -1)
        n1In = ePos;
      else
        n1In = sx.length();
      if (rPos != -1) {
        if (ePos != -1)
          n2In = ePos - rPos - 1;
        else
          n2In = sx.length() - rPos - 1;
      } else
        n2In = 0;
      if (ePos != -1) {
        int ie = ePos + 1;
        expon = 0;
        if (sx.charAt(ie) == '-') {
          for (++ie; ie < sx.length(); ie++)
            if (sx.charAt(ie) != '0')
              break;
          if (ie < sx.length())
            expon = -Integer.parseInt(sx.substring(ie));
        } else {
          if (sx.charAt(ie) == '+')
            ++ie;
          for (; ie < sx.length(); ie++)
            if (sx.charAt(ie) != '0')
              break;
          if (ie < sx.length())
            expon = Integer.parseInt(sx.substring(ie));
        }
      }
      if (rPos != -1)
        expon += rPos - 1;
      if (precisionSet)
        p = precision;
      else
        p = defaultDigits - 1;
      if (rPos != -1 && ePos != -1)
        ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos))
            .toCharArray();
      else if (rPos != -1)
        ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1))
            .toCharArray();
      else if (ePos != -1)
        ca1 = sx.substring(0, ePos).toCharArray();
      else
        ca1 = sx.toCharArray();
      boolean carry = false;
      int i0 = 0;
      if (ca1[0] != '0')
        i0 = 0;
      else
        for (i0 = 0; i0 < ca1.length; i0++)
          if (ca1[i0] != '0')
            break;
      if (i0 + p < ca1.length - 1) {
        carry = checkForCarry(ca1, i0 + p + 1);
        if (carry)
          carry = startSymbolicCarry(ca1, i0 + p, i0);
        if (carry) {
          ca2 = new char[i0 + p + 1];
          ca2[i0] = '1';
          for (j = 0; j < i0; j++)
            ca2[j] = '0';
          for (i = i0, j = i0 + 1; j < p + 1; i++, j++)
            ca2[j] = ca1[i];
          expon++;
          ca1 = ca2;
        }
      }
      if (Math.abs(expon) < 100 && !optionalL)
        eSize = 4;
      else
        eSize = 5;
      if (alternateForm || !precisionSet || precision != 0)
        ca2 = new char[2 + p + eSize];
      else
        ca2 = new char[1 + eSize];
      if (ca1[0] != '0') {
        ca2[0] = ca1[0];
        j = 1;
      } else {
        for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++)
          if (ca1[j] != '0')
            break;
        if ((ePos != -1 && j < ePos) || (ePos == -1 && j < ca1.length)) {
          ca2[0] = ca1[j];
          expon -= j;
          j++;
        } else {
          ca2[0] = '0';
          j = 2;
        }
      }
      if (alternateForm || !precisionSet || precision != 0) {
        ca2[1] = '.';
        i = 2;
      } else
        i = 1;
      for (k = 0; k < p && j < ca1.length; j++, i++, k++)
        ca2[i] = ca1[j];
      for (; i < ca2.length - eSize; i++)
        ca2[i] = '0';
      ca2[i++] = eChar;
      if (expon < 0)
        ca2[i++] = '-';
      else
        ca2[i++] = '+';
      expon = Math.abs(expon);
      if (expon >= 100) {
        switch (expon / 100) {
        case 1:
          ca2[i] = '1';
          break;
        case 2:
          ca2[i] = '2';
          break;
        case 3:
          ca2[i] = '3';
          break;
        case 4:
          ca2[i] = '4';
          break;
        case 5:
          ca2[i] = '5';
          break;
        case 6:
          ca2[i] = '6';
          break;
        case 7:
          ca2[i] = '7';
          break;
        case 8:
          ca2[i] = '8';
          break;
        case 9:
          ca2[i] = '9';
          break;
        }
        i++;
      }
      switch ((expon % 100) / 10) {
      case 0:
        ca2[i] = '0';
        break;
      case 1:
        ca2[i] = '1';
        break;
      case 2:
        ca2[i] = '2';
        break;
      case 3:
        ca2[i] = '3';
        break;
      case 4:
        ca2[i] = '4';
        break;
      case 5:
        ca2[i] = '5';
        break;
      case 6:
        ca2[i] = '6';
        break;
      case 7:
        ca2[i] = '7';
        break;
      case 8:
        ca2[i] = '8';
        break;
      case 9:
        ca2[i] = '9';
        break;
      }
      i++;
      switch (expon % 10) {
      case 0:
        ca2[i] = '0';
        break;
      case 1:
        ca2[i] = '1';
        break;
      case 2:
        ca2[i] = '2';
        break;
      case 3:
        ca2[i] = '3';
        break;
      case 4:
        ca2[i] = '4';
        break;
      case 5:
        ca2[i] = '5';
        break;
      case 6:
        ca2[i] = '6';
        break;
      case 7:
        ca2[i] = '7';
        break;
      case 8:
        ca2[i] = '8';
        break;
      case 9:
        ca2[i] = '9';
        break;
      }
      int nZeros = 0;
      if (!leftJustify && leadingZeros) {
        int xThousands = 0;
        if (thousands) {
          int xlead = 0;
          if (ca2[0] == '+' || ca2[0] == '-' || ca2[0] == ' ')
            xlead = 1;
          int xdp = xlead;
          for (; xdp < ca2.length; xdp++)
            if (ca2[xdp] == '.')
              break;
          xThousands = (xdp - xlead) / 3;
        }
        if (fieldWidthSet)
          nZeros = fieldWidth - ca2.length;
        if ((!minusSign && (leadingSign || leadingSpace)) || minusSign)
          nZeros--;
        nZeros -= xThousands;
        if (nZeros < 0)
          nZeros = 0;
      }
      j = 0;
      if ((!minusSign && (leadingSign || leadingSpace)) || minusSign) {
        ca3 = new char[ca2.length + nZeros + 1];
        j++;
      } else
        ca3 = new char[ca2.length + nZeros];
      if (!minusSign) {
        if (leadingSign)
          ca3[0] = '+';
        if (leadingSpace)
          ca3[0] = ' ';
      } else
        ca3[0] = '-';
      for (k = 0; k < nZeros; j++, k++)
        ca3[j] = '0';
      for (i = 0; i < ca2.length && j < ca3.length; i++, j++)
        ca3[j] = ca2[i];

      int lead = 0;
      if (ca3[0] == '+' || ca3[0] == '-' || ca3[0] == ' ')
        lead = 1;
      int dp = lead;
      for (; dp < ca3.length; dp++)
        if (ca3[dp] == '.')
          break;
      int nThousands = dp / 3;
      // Localize the decimal point.
      if (dp < ca3.length)
        ca3[dp] = dfs.getDecimalSeparator();
      char[] ca4 = ca3;
      if (thousands && nThousands > 0) {
        ca4 = new char[ca3.length + nThousands + lead];
        ca4[0] = ca3[0];
        for (i = lead, k = lead; i < dp; i++) {
          if (i > 0 && (dp - i) % 3 == 0) {
            // ca4[k]=',';
            ca4[k] = dfs.getGroupingSeparator();
            ca4[k + 1] = ca3[i];
            k += 2;
          } else {
            ca4[k] = ca3[i];
            k++;
          }
        }
        for (; i < ca3.length; i++, k++)
          ca4[k] = ca3[i];
      }
      return ca4;
    }

    /**
     * Check to see if the digits that are going to be truncated because of
     * the precision should force a round in the preceding digits.
     * 
     * @param ca1
     *            the array of digits
     * @param icarry
     *            the index of the first digit that is to be truncated from
     *            the print
     * @return <code>true</code> if the truncation forces a round that will
     *         change the print
     */
    private boolean checkForCarry(char[] ca1, int icarry) {
      boolean carry = false;
      if (icarry < ca1.length) {
        if (ca1[icarry] == '6' || ca1[icarry] == '7'
            || ca1[icarry] == '8' || ca1[icarry] == '9')
          carry = true;
        else if (ca1[icarry] == '5') {
          int ii = icarry + 1;
          for (; ii < ca1.length; ii++)
            if (ca1[ii] != '0')
              break;
          carry = ii < ca1.length;
          if (!carry && icarry > 0) {
            carry = (ca1[icarry - 1] == '1'
                || ca1[icarry - 1] == '3'
                || ca1[icarry - 1] == '5'
                || ca1[icarry - 1] == '7' || ca1[icarry - 1] == '9');
          }
        }
      }
      return carry;
    }

    /**
     * Start the symbolic carry process. The process is not quite finished
     * because the symbolic carry may change the length of the string and
     * change the exponent (in e format).
     * 
     * @param cLast
     *            index of the last digit changed by the round
     * @param cFirst
     *            index of the first digit allowed to be changed by this
     *            phase of the round
     * @return <code>true</code> if the carry forces a round that will
     *         change the print still more
     */
    private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) {
      boolean carry = true;
      for (int i = cLast; carry && i >= cFirst; i--) {
        carry = false;
        switch (ca[i]) {
        case '0':
          ca[i] = '1';
          break;
        case '1':
          ca[i] = '2';
          break;
        case '2':
          ca[i] = '3';
          break;
        case '3':
          ca[i] = '4';
          break;
        case '4':
          ca[i] = '5';
          break;
        case '5':
          ca[i] = '6';
          break;
        case '6':
          ca[i] = '7';
          break;
        case '7':
          ca[i] = '8';
          break;
        case '8':
          ca[i] = '9';
          break;
        case '9':
          ca[i] = '0';
          carry = true;
          break;
        }
      }
      return carry;
    }

    /**
     * An intermediate routine on the way to creating an e format String.
     * The method decides whether the input double value is an infinity,
     * not-a-number, or a finite double and formats each type of input
     * appropriately.
     * 
     * @param x
     *            the double value to be formatted.
     * @param eChar
     *            an 'e' or 'E' to use in the converted double value.
     * @return the converted double value.
     */
    private String eFormatString(double x, char eChar) {
      boolean noDigits = false;
      char[] ca4, ca5;
      if (Double.isInfinite(x)) {
        if (x == Double.POSITIVE_INFINITY) {
          if (leadingSign)
            ca4 = "+Inf".toCharArray();
          else if (leadingSpace)
            ca4 = " Inf".toCharArray();
          else
            ca4 = "Inf".toCharArray();
        } else
          ca4 = "-Inf".toCharArray();
        noDigits = true;
      } else if (Double.isNaN(x)) {
        if (leadingSign)
          ca4 = "+NaN".toCharArray();
        else if (leadingSpace)
          ca4 = " NaN".toCharArray();
        else
          ca4 = "NaN".toCharArray();
        noDigits = true;
      } else
        ca4 = eFormatDigits(x, eChar);
      ca5 = applyFloatPadding(ca4, false);
      return new String(ca5);
    }

    /**
     * Apply zero or blank, left or right padding.
     * 
     * @param ca4
     *            array of characters before padding is finished
     * @param noDigits
     *            NaN or signed Inf
     * @return a padded array of characters
     */
    private char[] applyFloatPadding(char[] ca4, boolean noDigits) {
      char[] ca5 = ca4;
      if (fieldWidthSet) {
        int i, j, nBlanks;
        if (leftJustify) {
          nBlanks = fieldWidth - ca4.length;
          if (nBlanks > 0) {
            ca5 = new char[ca4.length + nBlanks];
            for (i = 0; i < ca4.length; i++)
              ca5[i] = ca4[i];
            for (j = 0; j < nBlanks; j++, i++)
              ca5[i] = ' ';
          }
        } else if (!leadingZeros || noDigits) {
          nBlanks = fieldWidth - ca4.length;
          if (nBlanks > 0) {
            ca5 = new char[ca4.length + nBlanks];
            for (i = 0; i < nBlanks; i++)
              ca5[i] = ' ';
            for (j = 0; j < ca4.length; i++, j++)
              ca5[i] = ca4[j];
          }
        } else if (leadingZeros) {
          nBlanks = fieldWidth - ca4.length;
          if (nBlanks > 0) {
            ca5 = new char[ca4.length + nBlanks];
            i = 0;
            j = 0;
            if (ca4[0] == '-') {
              ca5[0] = '-';
              i++;
              j++;
            }
            for (int k = 0; k < nBlanks; i++, k++)
              ca5[i] = '0';
            for (; j < ca4.length; i++, j++)
              ca5[i] = ca4[j];
          }
        }
      }
      return ca5;
    }

    /**
     * Format method for the f conversion character.
     * 
     * @param x
     *            the double to format.
     * @return the formatted String.
     */
    private String printFFormat(double x) {
      return fFormatString(x);
    }

    /**
     * Format method for the e or E conversion character.
     * 
     * @param x
     *            the double to format.
     * @return the formatted String.
     */
    private String printEFormat(double x) {
      if (conversionCharacter == 'e')
        return eFormatString(x, 'e');
      else
        return eFormatString(x, 'E');
    }

    /**
     * Format method for the g conversion character.
     * 
     * For g format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. '+' character means that the conversion will always begin
     * with a sign (+ or -). The blank flag character means that a
     * non-negative input will be preceded with a blank. If both a '+' and a
     * ' ' are specified, the blank flag is ignored. The '0' flag character
     * implies that padding to the field width will be done with zeros
     * instead of blanks.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear
     * after the radix character. Padding is with trailing 0s.
     * 
     * @param x
     *            the double to format.
     * @return the formatted String.
     */
    private String printGFormat(double x) {
      String sx, sy, sz, ret;
      int savePrecision = precision;
      int i;
      char[] ca4, ca5;
      boolean noDigits = false;
      if (Double.isInfinite(x)) {
        if (x == Double.POSITIVE_INFINITY) {
          if (leadingSign)
            ca4 = "+Inf".toCharArray();
          else if (leadingSpace)
            ca4 = " Inf".toCharArray();
          else
            ca4 = "Inf".toCharArray();
        } else
          ca4 = "-Inf".toCharArray();
        noDigits = true;
      } else if (Double.isNaN(x)) {
        if (leadingSign)
          ca4 = "+NaN".toCharArray();
        else if (leadingSpace)
          ca4 = " NaN".toCharArray();
        else
          ca4 = "NaN".toCharArray();
        noDigits = true;
      } else {
        if (!precisionSet)
          precision = defaultDigits;
        if (precision == 0)
          precision = 1;
        int ePos = -1;
        if (conversionCharacter == 'g') {
          sx = eFormatString(x, 'e').trim();
          ePos = sx.indexOf('e');
        } else {
          sx = eFormatString(x, 'E').trim();
          ePos = sx.indexOf('E');
        }
        i = ePos + 1;
        int expon = 0;
        if (sx.charAt(i) == '-') {
          for (++i; i < sx.length(); i++)
            if (sx.charAt(i) != '0')
              break;
          if (i < sx.length())
            expon = -Integer.parseInt(sx.substring(i));
        } else {
          if (sx.charAt(i) == '+')
            ++i;
          for (; i < sx.length(); i++)
            if (sx.charAt(i) != '0')
              break;
          if (i < sx.length())
            expon = Integer.parseInt(sx.substring(i));
        }
        // Trim trailing zeros.
        // If the radix character is not followed by
        // a digit, trim it, too.
        if (!alternateForm) {
          if (expon >= -4 && expon < precision)
            sy = fFormatString(x).trim();
          else
            sy = sx.substring(0, ePos);
          i = sy.length() - 1;
          for (; i >= 0; i--)
            if (sy.charAt(i) != '0')
              break;
          if (i >= 0 && sy.charAt(i) == '.')
            i--;
          if (i == -1)
            sz = "0";
          else if (!Character.isDigit(sy.charAt(i)))
            sz = sy.substring(0, i + 1) + "0";
          else
            sz = sy.substring(0, i + 1);
          if (expon >= -4 && expon < precision)
            ret = sz;
          else
            ret = sz + sx.substring(ePos);
        } else {
          if (expon >= -4 && expon < precision)
            ret = fFormatString(x).trim();
          else
            ret = sx;
        }
        // leading space was trimmed off during
        // construction
        if (leadingSpace)
          if (x >= 0)
            ret = " " + ret;
        ca4 = ret.toCharArray();
      }
      // Pad with blanks or zeros.
      ca5 = applyFloatPadding(ca4, false);
      precision = savePrecision;
      return new String(ca5);
    }

    /**
     * Format method for the d conversion specifer and short argument.
     * 
     * For d format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. A '+' character means that the conversion will always begin
     * with a sign (+ or -). The blank flag character means that a
     * non-negative input will be preceded with a blank. If both a '+' and a
     * ' ' are specified, the blank flag is ignored. The '0' flag character
     * implies that padding to the field width will be done with zeros
     * instead of blanks.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the short to format.
     * @return the formatted String.
     */
    private String printDFormat(short x) {
      return printDFormat(Short.toString(x));
    }

    /**
     * Format method for the d conversion character and long argument.
     * 
     * For d format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. A '+' character means that the conversion will always begin
     * with a sign (+ or -). The blank flag character means that a
     * non-negative input will be preceded with a blank. If both a '+' and a
     * ' ' are specified, the blank flag is ignored. The '0' flag character
     * implies that padding to the field width will be done with zeros
     * instead of blanks.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the long to format.
     * @return the formatted String.
     */
    private String printDFormat(long x) {
      return printDFormat(Long.toString(x));
    }

    /**
     * Format method for the d conversion character and int argument.
     * 
     * For d format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. A '+' character means that the conversion will always begin
     * with a sign (+ or -). The blank flag character means that a
     * non-negative input will be preceded with a blank. If both a '+' and a
     * ' ' are specified, the blank flag is ignored. The '0' flag character
     * implies that padding to the field width will be done with zeros
     * instead of blanks.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the int to format.
     * @return the formatted String.
     */
    private String printDFormat(int x) {
      return printDFormat(Integer.toString(x));
    }

    /**
     * Utility method for formatting using the d conversion character.
     * 
     * @param sx
     *            the String to format, the result of converting a short,
     *            int, or long to a String.
     * @return the formatted String.
     */
    private String printDFormat(String sx) {
      int nLeadingZeros = 0;
      int nBlanks = 0, n = 0;
      int i = 0, jFirst = 0;
      boolean neg = sx.charAt(0) == '-';
      if (sx.equals("0") && precisionSet && precision == 0)
        sx = "";
      if (!neg) {
        if (precisionSet && sx.length() < precision)
          nLeadingZeros = precision - sx.length();
      } else {
        if (precisionSet && (sx.length() - 1) < precision)
          nLeadingZeros = precision - sx.length() + 1;
      }
      if (nLeadingZeros < 0)
        nLeadingZeros = 0;
      if (fieldWidthSet) {
        nBlanks = fieldWidth - nLeadingZeros - sx.length();
        if (!neg && (leadingSign || leadingSpace))
          nBlanks--;
      }
      if (nBlanks < 0)
        nBlanks = 0;
      if (leadingSign)
        n++;
      else if (leadingSpace)
        n++;
      n += nBlanks;
      n += nLeadingZeros;
      n += sx.length();
      char[] ca = new char[n];
      if (leftJustify) {
        if (neg)
          ca[i++] = '-';
        else if (leadingSign)
          ca[i++] = '+';
        else if (leadingSpace)
          ca[i++] = ' ';
        char[] csx = sx.toCharArray();
        jFirst = neg ? 1 : 0;
        for (int j = 0; j < nLeadingZeros; i++, j++)
          ca[i] = '0';
        for (int j = jFirst; j < csx.length; j++, i++)
          ca[i] = csx[j];
        for (int j = 0; j < nBlanks; i++, j++)
          ca[i] = ' ';
      } else {
        if (!leadingZeros) {
          for (i = 0; i < nBlanks; i++)
            ca[i] = ' ';
          if (neg)
            ca[i++] = '-';
          else if (leadingSign)
            ca[i++] = '+';
          else if (leadingSpace)
            ca[i++] = ' ';
        } else {
          if (neg)
            ca[i++] = '-';
          else if (leadingSign)
            ca[i++] = '+';
          else if (leadingSpace)
            ca[i++] = ' ';
          for (int j = 0; j < nBlanks; j++, i++)
            ca[i] = '0';
        }
        for (int j = 0; j < nLeadingZeros; j++, i++)
          ca[i] = '0';
        char[] csx = sx.toCharArray();
        jFirst = neg ? 1 : 0;
        for (int j = jFirst; j < csx.length; j++, i++)
          ca[i] = csx[j];
      }
      return new String(ca);
    }

    /**
     * Format method for the x conversion character and short argument.
     * 
     * For x format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. The '#' flag character means to lead with '0x'.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the short to format.
     * @return the formatted String.
     */
    private String printXFormat(short x) {
      String sx = null;
      if (x == Short.MIN_VALUE)
        sx = "8000";
      else if (x < 0) {
        String t;
        if (x == Short.MIN_VALUE)
          t = "0";
        else {
          t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16);
          if (t.charAt(0) == 'F' || t.charAt(0) == 'f')
            t = t.substring(16, 32);
        }
        switch (t.length()) {
        case 1:
          sx = "800" + t;
          break;
        case 2:
          sx = "80" + t;
          break;
        case 3:
          sx = "8" + t;
          break;
        case 4:
          switch (t.charAt(0)) {
          case '1':
            sx = "9" + t.substring(1, 4);
            break;
          case '2':
            sx = "a" + t.substring(1, 4);
            break;
          case '3':
            sx = "b" + t.substring(1, 4);
            break;
          case '4':
            sx = "c" + t.substring(1, 4);
            break;
          case '5':
            sx = "d" + t.substring(1, 4);
            break;
          case '6':
            sx = "e" + t.substring(1, 4);
            break;
          case '7':
            sx = "f" + t.substring(1, 4);
            break;
          }
          break;
        }
      } else
        sx = Integer.toString((int) x, 16);
      return printXFormat(sx);
    }

    /**
     * Format method for the x conversion character and long argument.
     * 
     * For x format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. The '#' flag character means to lead with '0x'.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the long to format.
     * @return the formatted String.
     */
    private String printXFormat(long x) {
      String sx = null;
      if (x == Long.MIN_VALUE)
        sx = "8000000000000000";
      else if (x < 0) {
        String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16);
        switch (t.length()) {
        case 1:
          sx = "800000000000000" + t;
          break;
        case 2:
          sx = "80000000000000" + t;
          break;
        case 3:
          sx = "8000000000000" + t;
          break;
        case 4:
          sx = "800000000000" + t;
          break;
        case 5:
          sx = "80000000000" + t;
          break;
        case 6:
          sx = "8000000000" + t;
          break;
        case 7:
          sx = "800000000" + t;
          break;
        case 8:
          sx = "80000000" + t;
          break;
        case 9:
          sx = "8000000" + t;
          break;
        case 10:
          sx = "800000" + t;
          break;
        case 11:
          sx = "80000" + t;
          break;
        case 12:
          sx = "8000" + t;
          break;
        case 13:
          sx = "800" + t;
          break;
        case 14:
          sx = "80" + t;
          break;
        case 15:
          sx = "8" + t;
          break;
        case 16:
          switch (t.charAt(0)) {
          case '1':
            sx = "9" + t.substring(1, 16);
            break;
          case '2':
            sx = "a" + t.substring(1, 16);
            break;
          case '3':
            sx = "b" + t.substring(1, 16);
            break;
          case '4':
            sx = "c" + t.substring(1, 16);
            break;
          case '5':
            sx = "d" + t.substring(1, 16);
            break;
          case '6':
            sx = "e" + t.substring(1, 16);
            break;
          case '7':
            sx = "f" + t.substring(1, 16);
            break;
          }
          break;
        }
      } else
        sx = Long.toString(x, 16);
      return printXFormat(sx);
    }

    /**
     * Format method for the x conversion character and int argument.
     * 
     * For x format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. The '#' flag character means to lead with '0x'.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the int to format.
     * @return the formatted String.
     */
    private String printXFormat(int x) {
      String sx = null;
      if (x == Integer.MIN_VALUE)
        sx = "80000000";
      else if (x < 0) {
        String t = Integer
            .toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16);
        switch (t.length()) {
        case 1:
          sx = "8000000" + t;
          break;
        case 2:
          sx = "800000" + t;
          break;
        case 3:
          sx = "80000" + t;
          break;
        case 4:
          sx = "8000" + t;
          break;
        case 5:
          sx = "800" + t;
          break;
        case 6:
          sx = "80" + t;
          break;
        case 7:
          sx = "8" + t;
          break;
        case 8:
          switch (t.charAt(0)) {
          case '1':
            sx = "9" + t.substring(1, 8);
            break;
          case '2':
            sx = "a" + t.substring(1, 8);
            break;
          case '3':
            sx = "b" + t.substring(1, 8);
            break;
          case '4':
            sx = "c" + t.substring(1, 8);
            break;
          case '5':
            sx = "d" + t.substring(1, 8);
            break;
          case '6':
            sx = "e" + t.substring(1, 8);
            break;
          case '7':
            sx = "f" + t.substring(1, 8);
            break;
          }
          break;
        }
      } else
        sx = Integer.toString(x, 16);
      return printXFormat(sx);
    }

    /**
     * Utility method for formatting using the x conversion character.
     * 
     * @param sx
     *            the String to format, the result of converting a short,
     *            int, or long to a String.
     * @return the formatted String.
     */
    private String printXFormat(String sx) {
      int nLeadingZeros = 0;
      int nBlanks = 0;
      if (sx.equals("0") && precisionSet && precision == 0)
        sx = "";
      if (precisionSet)
        nLeadingZeros = precision - sx.length();
      if (nLeadingZeros < 0)
        nLeadingZeros = 0;
      if (fieldWidthSet) {
        nBlanks = fieldWidth - nLeadingZeros - sx.length();
        if (alternateForm)
          nBlanks = nBlanks - 2;
      }
      if (nBlanks < 0)
        nBlanks = 0;
      int n = 0;
      if (alternateForm)
        n += 2;
      n += nLeadingZeros;
      n += sx.length();
      n += nBlanks;
      char[] ca = new char[n];
      int i = 0;
      if (leftJustify) {
        if (alternateForm) {
          ca[i++] = '0';
          ca[i++] = 'x';
        }
        for (int j = 0; j < nLeadingZeros; j++, i++)
          ca[i] = '0';
        char[] csx = sx.toCharArray();
        for (int j = 0; j < csx.length; j++, i++)
          ca[i] = csx[j];
        for (int j = 0; j < nBlanks; j++, i++)
          ca[i] = ' ';
      } else {
        if (!leadingZeros)
          for (int j = 0; j < nBlanks; j++, i++)
            ca[i] = ' ';
        if (alternateForm) {
          ca[i++] = '0';
          ca[i++] = 'x';
        }
        if (leadingZeros)
          for (int j = 0; j < nBlanks; j++, i++)
            ca[i] = '0';
        for (int j = 0; j < nLeadingZeros; j++, i++)
          ca[i] = '0';
        char[] csx = sx.toCharArray();
        for (int j = 0; j < csx.length; j++, i++)
          ca[i] = csx[j];
      }
      String caReturn = new String(ca);
      if (conversionCharacter == 'X')
        caReturn = caReturn.toUpperCase();
      return caReturn;
    }

    /**
     * Format method for the o conversion character and short argument.
     * 
     * For o format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. The '#' flag character means that the output begins with a
     * leading 0 and the precision is increased by 1.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the short to format.
     * @return the formatted String.
     */
    private String printOFormat(short x) {
      String sx = null;
      if (x == Short.MIN_VALUE)
        sx = "100000";
      else if (x < 0) {
        String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8);
        switch (t.length()) {
        case 1:
          sx = "10000" + t;
          break;
        case 2:
          sx = "1000" + t;
          break;
        case 3:
          sx = "100" + t;
          break;
        case 4:
          sx = "10" + t;
          break;
        case 5:
          sx = "1" + t;
          break;
        }
      } else
        sx = Integer.toString((int) x, 8);
      return printOFormat(sx);
    }

    /**
     * Format method for the o conversion character and long argument.
     * 
     * For o format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. The '#' flag character means that the output begins with a
     * leading 0 and the precision is increased by 1.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the long to format.
     * @return the formatted String.
     */
    private String printOFormat(long x) {
      String sx = null;
      if (x == Long.MIN_VALUE)
        sx = "1000000000000000000000";
      else if (x < 0) {
        String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8);
        switch (t.length()) {
        case 1:
          sx = "100000000000000000000" + t;
          break;
        case 2:
          sx = "10000000000000000000" + t;
          break;
        case 3:
          sx = "1000000000000000000" + t;
          break;
        case 4:
          sx = "100000000000000000" + t;
          break;
        case 5:
          sx = "10000000000000000" + t;
          break;
        case 6:
          sx = "1000000000000000" + t;
          break;
        case 7:
          sx = "100000000000000" + t;
          break;
        case 8:
          sx = "10000000000000" + t;
          break;
        case 9:
          sx = "1000000000000" + t;
          break;
        case 10:
          sx = "100000000000" + t;
          break;
        case 11:
          sx = "10000000000" + t;
          break;
        case 12:
          sx = "1000000000" + t;
          break;
        case 13:
          sx = "100000000" + t;
          break;
        case 14:
          sx = "10000000" + t;
          break;
        case 15:
          sx = "1000000" + t;
          break;
        case 16:
          sx = "100000" + t;
          break;
        case 17:
          sx = "10000" + t;
          break;
        case 18:
          sx = "1000" + t;
          break;
        case 19:
          sx = "100" + t;
          break;
        case 20:
          sx = "10" + t;
          break;
        case 21:
          sx = "1" + t;
          break;
        }
      } else
        sx = Long.toString(x, 8);
      return printOFormat(sx);
    }

    /**
     * Format method for the o conversion character and int argument.
     * 
     * For o format, the flag character '-', means that the output should be
     * left justified within the field. The default is to pad with blanks on
     * the left. The '#' flag character means that the output begins with a
     * leading 0 and the precision is increased by 1.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is to add no padding. Padding is with blanks by
     * default.
     * 
     * The precision, if set, is the minimum number of digits to appear.
     * Padding is with leading 0s.
     * 
     * @param x
     *            the int to format.
     * @return the formatted String.
     */
    private String printOFormat(int x) {
      String sx = null;
      if (x == Integer.MIN_VALUE)
        sx = "20000000000";
      else if (x < 0) {
        String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8);
        switch (t.length()) {
        case 1:
          sx = "2000000000" + t;
          break;
        case 2:
          sx = "200000000" + t;
          break;
        case 3:
          sx = "20000000" + t;
          break;
        case 4:
          sx = "2000000" + t;
          break;
        case 5:
          sx = "200000" + t;
          break;
        case 6:
          sx = "20000" + t;
          break;
        case 7:
          sx = "2000" + t;
          break;
        case 8:
          sx = "200" + t;
          break;
        case 9:
          sx = "20" + t;
          break;
        case 10:
          sx = "2" + t;
          break;
        case 11:
          sx = "3" + t.substring(1);
          break;
        }
      } else
        sx = Integer.toString(x, 8);
      return printOFormat(sx);
    }

    /**
     * Utility method for formatting using the o conversion character.
     * 
     * @param sx
     *            the String to format, the result of converting a short,
     *            int, or long to a String.
     * @return the formatted String.
     */
    private String printOFormat(String sx) {
      int nLeadingZeros = 0;
      int nBlanks = 0;
      if (sx.equals("0") && precisionSet && precision == 0)
        sx = "";
      if (precisionSet)
        nLeadingZeros = precision - sx.length();
      if (alternateForm)
        nLeadingZeros++;
      if (nLeadingZeros < 0)
        nLeadingZeros = 0;
      if (fieldWidthSet)
        nBlanks = fieldWidth - nLeadingZeros - sx.length();
      if (nBlanks < 0)
        nBlanks = 0;
      int n = nLeadingZeros + sx.length() + nBlanks;
      char[] ca = new char[n];
      int i;
      if (leftJustify) {
        for (i = 0; i < nLeadingZeros; i++)
          ca[i] = '0';
        char[] csx = sx.toCharArray();
        for (int j = 0; j < csx.length; j++, i++)
          ca[i] = csx[j];
        for (int j = 0; j < nBlanks; j++, i++)
          ca[i] = ' ';
      } else {
        if (leadingZeros)
          for (i = 0; i < nBlanks; i++)
            ca[i] = '0';
        else
          for (i = 0; i < nBlanks; i++)
            ca[i] = ' ';
        for (int j = 0; j < nLeadingZeros; j++, i++)
          ca[i] = '0';
        char[] csx = sx.toCharArray();
        for (int j = 0; j < csx.length; j++, i++)
          ca[i] = csx[j];
      }
      return new String(ca);
    }

    /**
     * Format method for the c conversion character and char argument.
     * 
     * The only flag character that affects c format is the '-', meaning
     * that the output should be left justified within the field. The
     * default is to pad with blanks on the left.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. Padding is with blanks by default. The default width is 1.
     * 
     * The precision, if set, is ignored.
     * 
     * @param x
     *            the char to format.
     * @return the formatted String.
     */
    private String printCFormat(char x) {
      int nPrint = 1;
      int width = fieldWidth;
      if (!fieldWidthSet)
        width = nPrint;
      char[] ca = new char[width];
      int i = 0;
      if (leftJustify) {
        ca[0] = x;
        for (i = 1; i <= width - nPrint; i++)
          ca[i] = ' ';
      } else {
        for (i = 0; i < width - nPrint; i++)
          ca[i] = ' ';
        ca[i] = x;
      }
      return new String(ca);
    }

    /**
     * Format method for the s conversion character and String argument.
     * 
     * The only flag character that affects s format is the '-', meaning
     * that the output should be left justified within the field. The
     * default is to pad with blanks on the left.
     * 
     * The field width is treated as the minimum number of characters to be
     * printed. The default is the smaller of the number of characters in
     * the the input and the precision. Padding is with blanks by default.
     * 
     * The precision, if set, specifies the maximum number of characters to
     * be printed from the string. A null digit string is treated as a 0.
     * The default is not to set a maximum number of characters to be
     * printed.
     * 
     * @param x
     *            the String to format.
     * @return the formatted String.
     */
    private String printSFormat(String x) {
      int nPrint = x.length();
      int width = fieldWidth;
      if (precisionSet && nPrint > precision)
        nPrint = precision;
      if (!fieldWidthSet)
        width = nPrint;
      int n = 0;
      if (width > nPrint)
        n += width - nPrint;
      if (nPrint >= x.length())
        n += x.length();
      else
        n += nPrint;
      char[] ca = new char[n];
      int i = 0;
      if (leftJustify) {
        if (nPrint >= x.length()) {
          char[] csx = x.toCharArray();
          for (i = 0; i < x.length(); i++)
            ca[i] = csx[i];
        } else {
          char[] csx = x.substring(0, nPrint).toCharArray();
          for (i = 0; i < nPrint; i++)
            ca[i] = csx[i];
        }
        for (int j = 0; j < width - nPrint; j++, i++)
          ca[i] = ' ';
      } else {
        for (i = 0; i < width - nPrint; i++)
          ca[i] = ' ';
        if (nPrint >= x.length()) {
          char[] csx = x.toCharArray();
          for (int j = 0; j < x.length(); i++, j++)
            ca[i] = csx[j];
        } else {
          char[] csx = x.substring(0, nPrint).toCharArray();
          for (int j = 0; j < nPrint; i++, j++)
            ca[i] = csx[j];
        }
      }
      return new String(ca);
    }

    /**
     * Check for a conversion character. If it is there, store it.
     * 
     * @param x
     *            the String to format.
     * @return <code>true</code> if the conversion character is there, and
     *         <code>false</code> otherwise.
     */
    private boolean setConversionCharacter() {
      /* idfgGoxXeEcs */
      boolean ret = false;
      conversionCharacter = '\0';
      if (pos < fmt.length()) {
        char c = fmt.charAt(pos);
        if (c == 'i' || c == 'd' || c == 'f' || c == 'g' || c == 'G'
            || c == 'o' || c == 'x' || c == 'X' || c == 'e'
            || c == 'E' || c == 'c' || c == 's' || c == '%') {
          conversionCharacter = c;
          pos++;
          ret = true;
        }
      }
      return ret;
    }

    /**
     * Check for an h, l, or L in a format. An L is used to control the
     * minimum number of digits in an exponent when using floating point
     * formats. An l or h is used to control conversion of the input to a
     * long or short, respectively, before formatting. If any of these is
     * present, store them.
     */
    private void setOptionalHL() {
      optionalh = false;
      optionall = false;
      optionalL = false;
      if (pos < fmt.length()) {
        char c = fmt.charAt(pos);
        if (c == 'h') {
          optionalh = true;
          pos++;
        } else if (c == 'l') {
          optionall = true;
          pos++;
        } else if (c == 'L') {
          optionalL = true;
          pos++;
        }
      }
    }

    /**
     * Set the precision.
     */
    private void setPrecision() {
      int firstPos = pos;
      precisionSet = false;
      if (pos < fmt.length() && fmt.charAt(pos) == '.') {
        pos++;
        if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) {
          pos++;
          if (!setPrecisionArgPosition()) {
            variablePrecision = true;
            precisionSet = true;
          }
          return;
        } else {
          while (pos < fmt.length()) {
            char c = fmt.charAt(pos);
            if (Character.isDigit(c))
              pos++;
            else
              break;
          }
          if (pos > firstPos + 1) {
            String sz = fmt.substring(firstPos + 1, pos);
            precision = Integer.parseInt(sz);
            precisionSet = true;
          }
        }
      }
    }

    /**
     * Set the field width.
     */
    private void setFieldWidth() {
      int firstPos = pos;
      fieldWidth = 0;
      fieldWidthSet = false;
      if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) {
        pos++;
        if (!setFieldWidthArgPosition()) {
          variableFieldWidth = true;
          fieldWidthSet = true;
        }
      } else {
        while (pos < fmt.length()) {
          char c = fmt.charAt(pos);
          if (Character.isDigit(c))
            pos++;
          else
            break;
        }
        if (firstPos < pos && firstPos < fmt.length()) {
          String sz = fmt.substring(firstPos, pos);
          fieldWidth = Integer.parseInt(sz);
          fieldWidthSet = true;
        }
      }
    }

    /**
     * Store the digits <code>n</code> in %n$ forms.
     */
    private void setArgPosition() {
      int xPos;
      for (xPos = pos; xPos < fmt.length(); xPos++) {
        if (!Character.isDigit(fmt.charAt(xPos)))
          break;
      }
      if (xPos > pos && xPos < fmt.length()) {
        if (fmt.charAt(xPos) == '$') {
          positionalSpecification = true;
          argumentPosition = Integer.parseInt(fmt
              .substring(pos, xPos));
          pos = xPos + 1;
        }
      }
    }

    /**
     * Store the digits <code>n</code> in *n$ forms.
     */
    private boolean setFieldWidthArgPosition() {
      boolean ret = false;
      int xPos;
      for (xPos = pos; xPos < fmt.length(); xPos++) {
        if (!Character.isDigit(fmt.charAt(xPos)))
          break;
      }
      if (xPos > pos && xPos < fmt.length()) {
        if (fmt.charAt(xPos) == '$') {
          positionalFieldWidth = true;
          argumentPositionForFieldWidth = Integer.parseInt(fmt
              .substring(pos, xPos));
          pos = xPos + 1;
          ret = true;
        }
      }
      return ret;
    }

    /**
     * Store the digits <code>n</code> in *n$ forms.
     */
    private boolean setPrecisionArgPosition() {
      boolean ret = false;
      int xPos;
      for (xPos = pos; xPos < fmt.length(); xPos++) {
        if (!Character.isDigit(fmt.charAt(xPos)))
          break;
      }
      if (xPos > pos && xPos < fmt.length()) {
        if (fmt.charAt(xPos) == '$') {
          positionalPrecision = true;
          argumentPositionForPrecision = Integer.parseInt(fmt
              .substring(pos, xPos));
          pos = xPos + 1;
          ret = true;
        }
      }
      return ret;
    }

    boolean isPositionalSpecification() {
      return positionalSpecification;
    }

    int getArgumentPosition() {
      return argumentPosition;
    }

    boolean isPositionalFieldWidth() {
      return positionalFieldWidth;
    }

    int getArgumentPositionForFieldWidth() {
      return argumentPositionForFieldWidth;
    }

    boolean isPositionalPrecision() {
      return positionalPrecision;
    }

    int getArgumentPositionForPrecision() {
      return argumentPositionForPrecision;
    }

    /**
     * Set flag characters, one of '-+#0 or a space.
     */
    private void setFlagCharacters() {
      /* '-+ #0 */
      thousands = false;
      leftJustify = false;
      leadingSign = false;
      leadingSpace = false;
      alternateForm = false;
      leadingZeros = false;
      for (; pos < fmt.length(); pos++) {
        char c = fmt.charAt(pos);
        if (c == '\'')
          thousands = true;
        else if (c == '-') {
          leftJustify = true;
          leadingZeros = false;
        } else if (c == '+') {
          leadingSign = true;
          leadingSpace = false;
        } else if (c == ' ') {
          if (!leadingSign)
            leadingSpace = true;
        } else if (c == '#')
          alternateForm = true;
        else if (c == '0') {
          if (!leftJustify)
            leadingZeros = true;
        } else
          break;
      }
    }

    /**
     * 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;
}

   
    
    
    
    
    
    
  








Related examples in the same category

1.The Uppercase Option
2.Using the Format Flags
3.The Format Specifiers
4.NumberFormat with Constant Locale UsageNumberFormat with Constant Locale Usage
5.Number Format by locale
6.demonstrates the %n and %% format specifiers:
7.demonstrates the minimum field-width specifier by applying it to the %f conversion:
8.Create a table of squares and cubes.
9.precision modifier: Format 4 decimal places
10.precision modifier: Format to 2 decimal places in a 16 character field
11.precision modifier: Display at most 15 characters in a string
12.left justification: Right justify by default
13.left justification: left justify
14.Demonstrate the space format specifiers.
15.Using an Argument Index
16.the NumberFormat object is created once when the program starts.
17.Default rounding mode
18.RoundingMode.HALF_DOWN
19.RoundingMode.FLOOR
20.RoundingMode.CEILING
21.Format a number our way and the default way
22.Format a number to currencyFormat a number to currency
23.Number Format with LocaleNumber Format with Locale
24.Add leading zeroes to a number
25.Decimal Format DemoDecimal Format Demo
26.Parse number with NumberFormat and Locale
27.Formatting and Parsing a Locale-Specific Percentage
28.Format a number with DecimalFormat
29.Parse a number with NumberFormat and Locale.CANADA
30.Format a number with leading zeroes
31.Format a number for a locale
32.Formatting and Parsing a Number for a Locale
33.Display numbers in scientific notation
34.Format for GERMAN locale
35.Format for the default locale
36.Displaying numbers with commas
37.Formatting a Number in Exponential Notation
38.Using only 0's to the left of E forces no decimal point
39.Parse a GERMAN number
40.Formatting and Parsing Locale-Specific Currency
41.Parse a number for a locale
42.Use grouping to display a number
43.Number format viewer
44.A number formatter for logarithmic values. This formatter does not support parsing.
45.A custom number formatter that formats numbers as hexadecimal strings.
46.NumberFormat and locale
47.Parse number with format