// // (c) 2000 Sun Microsystems, Inc. // ALL RIGHTS RESERVED // // License Grant- // // // Permission to use, copy, modify, and distribute this Software and its // documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is // hereby granted. // // This Software is provided "AS IS". All express warranties, including any // implied warranty of merchantability, satisfactory quality, fitness for a // particular purpose, or non-infringement, are disclaimed, except to the extent // that such disclaimers are held to be legally invalid. // // You acknowledge that Software is not designed, licensed or intended for use in // the design, construction, operation or maintenance of any nuclear facility // ("High Risk Activities"). Sun disclaims any express or implied warranty of // fitness for such uses. // // Please refer to the file http://www.sun.com/policies/trademarks/ for further // important trademark information and to // http://java.sun.com/nav/business/index.html for further important licensing // information for the Java Technology. // package marytts.util.string; 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> * 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> * 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> * 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> * * Escape Sequences * <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> * <caption>escape sequences</caption> * </table> * <p> * Conversion Specifications * </p> * <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 minimum 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> * <p> * Flag Characters * </p> * <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).</dd> * <dt>+ * <dd>result of a signed conversion always begins with a sign (+ or -). (It will begin with a sign only when a negative value is * converted if this flag is not specified.) * <dt><space> * <dd>If the first character of a signed conversion is not a sign, a space character will be placed before the result. This means * that if the space character and + flags both appear, the space flag will be ignored. * <dt># * <dd>value is to be converted to an alternative form. For c, d, i, and s conversions, the flag has no effect. For o conversion, * it increases the precision to force the first digit of the result to be a zero. For x or X conversion, a non-zero result has 0x * or 0X prefixed to it, respectively. For e, E, f, g, and G conversions, the result always contains a radix character, even if no * digits follow the radix character (normally, a decimal point appears in the result of these conversions only if a digit follows * it). For g and G conversions, trailing zeros will not be removed from the result as they normally are. * <dt>0 * <dd>d, i, o, x, X, e, E, f, g, and G conversions, leading zeros (following any indication of sign or base) are used to pad to * the field width; no space padding is performed. If the 0 and - flags both appear, the 0 flag is ignored. For d, i, o, x, and X * conversions, if a precision is specified, the 0 flag will be ignored. For c conversions, the flag is ignored. * </dl> * * <p> * Conversion Characters * </p> * <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... */ @Deprecated 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 locale * locale * @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; StringBuilder sb = new StringBuilder(); 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; StringBuilder sb = new StringBuilder(); 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; StringBuilder sb = new StringBuilder(); 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; StringBuilder sb = new StringBuilder(); 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; StringBuilder sb = new StringBuilder(); 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; StringBuilder sb = new StringBuilder(); 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; StringBuilder sb = new StringBuilder(); 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() { StringBuilder sb = new StringBuilder(); 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; }