Mega Code Archive

 
Categories / Java / Data Type
 

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