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.util.Enumeration; import java.util.Vector; import java.util.Locale; import java.text.DecimalFormatSymbols; /** * 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>ButtonCondActionFlag 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><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> * *<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; /** * ButtonCondActionFlag 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; /** * ButtonCondActionFlag indicating that left padding with zeroes is * specified. */ private boolean leadingZeros = false; /** * ButtonCondActionFlag 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; /** * ButtonCondActionFlag 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; /** * ButtonCondActionFlag indicating that the precision is *. */ private boolean variablePrecision = false; /** * ButtonCondActionFlag 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; /** * ButtonCondActionFlag specifying that a following d, i, o, u, x, * or X conversion character applies to a type * short int. */ private boolean optionalh = false; /** * ButtonCondActionFlag specifying that a following d, i, o, u, x, * or X conversion character applies to a type lont * int argument. */ private boolean optionall = false; /** * ButtonCondActionFlag 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; }