0001: package org.pnuts.text; // <= added
0002:
0003: //@(#)PrintfFormat.java 1.2 04/12/06// (c) 2000 Sun Microsystems, Inc.
0004: // ALL RIGHTS RESERVED
0005: //
0006: // License Grant-
0007: //
0008: //
0009: // Permission to use, copy, modify, and distribute this Software and its
0010: // documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is
0011: // hereby granted.
0012: //
0013: // This Software is provided "AS IS". All express warranties, including any
0014: // implied warranty of merchantability, satisfactory quality, fitness for a
0015: // particular purpose, or non-infringement, are disclaimed, except to the extent
0016: // that such disclaimers are held to be legally invalid.
0017: //
0018: // You acknowledge that Software is not designed, licensed or intended for use in
0019: // the design, construction, operation or maintenance of any nuclear facility
0020: // ("High Risk Activities"). Sun disclaims any express or implied warranty of
0021: // fitness for such uses.
0022: //
0023: // Please refer to the file http://www.sun.com/policies/trademarks/ for further
0024: // important trademark information and to
0025: // http://java.sun.com/nav/business/index.html for further important licensing
0026: // information for the Java Technology.
0027: //
0028:
0029: import java.util.Enumeration;
0030: import java.util.Vector;
0031: import java.util.Locale;
0032: import java.text.DecimalFormatSymbols;
0033:
0034: /**
0035: * PrintfFormat allows the formatting of an array of
0036: * objects embedded within a string. Primitive types
0037: * must be passed using wrapper types. The formatting
0038: * is controlled by a control string.
0039: *<p>
0040: * A control string is a Java string that contains a
0041: * control specification. The control specification
0042: * starts at the first percent sign (%) in the string,
0043: * provided that this percent sign
0044: *<ol>
0045: *<li>is not escaped protected by a matching % or is
0046: * not an escape % character,
0047: *<li>is not at the end of the format string, and
0048: *<li>precedes a sequence of characters that parses as
0049: * a valid control specification.
0050: *</ol>
0051: *</p><p>
0052: * A control specification usually takes the form:
0053: *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
0054: * { [hlL] }+ [idfgGoxXeEcs]
0055: *</pre>
0056: * There are variants of this basic form that are
0057: * discussed below.</p>
0058: *<p>
0059: * The format is composed of zero or more directives
0060: * defined as follows:
0061: *<ul>
0062: *<li>ordinary characters, which are simply copied to
0063: * the output stream;
0064: *<li>escape sequences, which represent non-graphic
0065: * characters; and
0066: *<li>conversion specifications, each of which
0067: * results in the fetching of zero or more arguments.
0068: *</ul></p>
0069: *<p>
0070: * The results are undefined if there are insufficient
0071: * arguments for the format. Usually an unchecked
0072: * exception will be thrown. If the format is
0073: * exhausted while arguments remain, the excess
0074: * arguments are evaluated but are otherwise ignored.
0075: * In format strings containing the % form of
0076: * conversion specifications, each argument in the
0077: * argument list is used exactly once.</p>
0078: * <p>
0079: * Conversions can be applied to the <code>n</code>th
0080: * argument after the format in the argument list,
0081: * rather than to the next unused argument. In this
0082: * case, the conversion characer % is replaced by the
0083: * sequence %<code>n</code>$, where <code>n</code> is
0084: * a decimal integer giving the position of the
0085: * argument in the argument list.</p>
0086: * <p>
0087: * In format strings containing the %<code>n</code>$
0088: * form of conversion specifications, each argument
0089: * in the argument list is used exactly once.</p>
0090: *
0091: *<h4>Escape Sequences</h4>
0092: *<p>
0093: * The following table lists escape sequences and
0094: * associated actions on display devices capable of
0095: * the action.
0096: *<table>
0097: *<tr><th align=left>Sequence</th>
0098: * <th align=left>Name</th>
0099: * <th align=left>Description</th></tr>
0100: *<tr><td>\\</td><td>backlash</td><td>None.
0101: *</td></tr>
0102: *<tr><td>\a</td><td>alert</td><td>Attempts to alert
0103: * the user through audible or visible
0104: * notification.
0105: *</td></tr>
0106: *<tr><td>\b</td><td>backspace</td><td>Moves the
0107: * printing position to one column before
0108: * the current position, unless the
0109: * current position is the start of a line.
0110: *</td></tr>
0111: *<tr><td>\f</td><td>form-feed</td><td>Moves the
0112: * printing position to the initial
0113: * printing position of the next logical
0114: * page.
0115: *</td></tr>
0116: *<tr><td>\n</td><td>newline</td><td>Moves the
0117: * printing position to the start of the
0118: * next line.
0119: *</td></tr>
0120: *<tr><td>\r</td><td>carriage-return</td><td>Moves
0121: * the printing position to the start of
0122: * the current line.
0123: *</td></tr>
0124: *<tr><td>\t</td><td>tab</td><td>Moves the printing
0125: * position to the next implementation-
0126: * defined horizontal tab position.
0127: *</td></tr>
0128: *<tr><td>\v</td><td>vertical-tab</td><td>Moves the
0129: * printing position to the start of the
0130: * next implementation-defined vertical
0131: * tab position.
0132: *</td></tr>
0133: *</table></p>
0134: *<h4>Conversion Specifications</h4>
0135: *<p>
0136: * Each conversion specification is introduced by
0137: * the percent sign character (%). After the character
0138: * %, the following appear in sequence:</p>
0139: *<p>
0140: * Zero or more flags (in any order), which modify the
0141: * meaning of the conversion specification.</p>
0142: *<p>
0143: * An optional minimum field width. If the converted
0144: * value has fewer characters than the field width, it
0145: * will be padded with spaces by default on the left;
0146: * t will be padded on the right, if the left-
0147: * adjustment flag (-), described below, is given to
0148: * the field width. The field width takes the form
0149: * of a decimal integer. If the conversion character
0150: * is s, the field width is the the minimum number of
0151: * characters to be printed.</p>
0152: *<p>
0153: * An optional precision that gives the minumum number
0154: * of digits to appear for the d, i, o, x or X
0155: * conversions (the field is padded with leading
0156: * zeros); the number of digits to appear after the
0157: * radix character for the e, E, and f conversions,
0158: * the maximum number of significant digits for the g
0159: * and G conversions; or the maximum number of
0160: * characters to be written from a string is s and S
0161: * conversions. The precision takes the form of an
0162: * optional decimal digit string, where a null digit
0163: * string is treated as 0. If a precision appears
0164: * with a c conversion character the precision is
0165: * ignored.
0166: * </p>
0167: *<p>
0168: * An optional h specifies that a following d, i, o,
0169: * x, or X conversion character applies to a type
0170: * short argument (the argument will be promoted
0171: * according to the integral promotions and its value
0172: * converted to type short before printing).</p>
0173: *<p>
0174: * An optional l (ell) specifies that a following
0175: * d, i, o, x, or X conversion character applies to a
0176: * type long argument.</p>
0177: *<p>
0178: * A field width or precision may be indicated by an
0179: * asterisk (*) instead of a digit string. In this
0180: * case, an integer argument supplised the field width
0181: * precision. The argument that is actually converted
0182: * is not fetched until the conversion letter is seen,
0183: * so the the arguments specifying field width or
0184: * precision must appear before the argument (if any)
0185: * to be converted. If the precision argument is
0186: * negative, it will be changed to zero. A negative
0187: * field width argument is taken as a - flag, followed
0188: * by a positive field width.</p>
0189: * <p>
0190: * In format strings containing the %<code>n</code>$
0191: * form of a conversion specification, a field width
0192: * or precision may be indicated by the sequence
0193: * *<code>m</code>$, where m is a decimal integer
0194: * giving the position in the argument list (after the
0195: * format argument) of an integer argument containing
0196: * the field width or precision.</p>
0197: * <p>
0198: * The format can contain either numbered argument
0199: * specifications (that is, %<code>n</code>$ and
0200: * *<code>m</code>$), or unnumbered argument
0201: * specifications (that is % and *), but normally not
0202: * both. The only exception to this is that %% can
0203: * be mixed with the %<code>n</code>$ form. The
0204: * results of mixing numbered and unnumbered argument
0205: * specifications in a format string are undefined.</p>
0206: *
0207: *<h4>Flag Characters</h4>
0208: *<p>
0209: * The flags and their meanings are:</p>
0210: *<dl>
0211: * <dt>'<dd> integer portion of the result of a
0212: * decimal conversion (%i, %d, %f, %g, or %G) will
0213: * be formatted with thousands' grouping
0214: * characters. For other conversions the flag
0215: * is ignored. The non-monetary grouping
0216: * character is used.
0217: * <dt>-<dd> result of the conversion is left-justified
0218: * within the field. (It will be right-justified
0219: * if this flag is not specified).</td></tr>
0220: * <dt>+<dd> result of a signed conversion always
0221: * begins with a sign (+ or -). (It will begin
0222: * with a sign only when a negative value is
0223: * converted if this flag is not specified.)
0224: * <dt><space><dd> If the first character of a
0225: * signed conversion is not a sign, a space
0226: * character will be placed before the result.
0227: * This means that if the space character and +
0228: * flags both appear, the space flag will be
0229: * ignored.
0230: * <dt>#<dd> value is to be converted to an alternative
0231: * form. For c, d, i, and s conversions, the flag
0232: * has no effect. For o conversion, it increases
0233: * the precision to force the first digit of the
0234: * result to be a zero. For x or X conversion, a
0235: * non-zero result has 0x or 0X prefixed to it,
0236: * respectively. For e, E, f, g, and G
0237: * conversions, the result always contains a radix
0238: * character, even if no digits follow the radix
0239: * character (normally, a decimal point appears in
0240: * the result of these conversions only if a digit
0241: * follows it). For g and G conversions, trailing
0242: * zeros will not be removed from the result as
0243: * they normally are.
0244: * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G
0245: * conversions, leading zeros (following any
0246: * indication of sign or base) are used to pad to
0247: * the field width; no space padding is
0248: * performed. If the 0 and - flags both appear,
0249: * the 0 flag is ignored. For d, i, o, x, and X
0250: * conversions, if a precision is specified, the
0251: * 0 flag will be ignored. For c conversions,
0252: * the flag is ignored.
0253: *</dl>
0254: *
0255: *<h4>Conversion Characters</h4>
0256: *<p>
0257: * Each conversion character results in fetching zero
0258: * or more arguments. The results are undefined if
0259: * there are insufficient arguments for the format.
0260: * Usually, an unchecked exception will be thrown.
0261: * If the format is exhausted while arguments remain,
0262: * the excess arguments are ignored.</p>
0263: *
0264: *<p>
0265: * The conversion characters and their meanings are:
0266: *</p>
0267: *<dl>
0268: * <dt>d,i<dd>The int argument is converted to a
0269: * signed decimal in the style [-]dddd. The
0270: * precision specifies the minimum number of
0271: * digits to appear; if the value being
0272: * converted can be represented in fewer
0273: * digits, it will be expanded with leading
0274: * zeros. The default precision is 1. The
0275: * result of converting 0 with an explicit
0276: * precision of 0 is no characters.
0277: * <dt>o<dd> The int argument is converted to unsigned
0278: * octal format in the style ddddd. The
0279: * precision specifies the minimum number of
0280: * digits to appear; if the value being
0281: * converted can be represented in fewer
0282: * digits, it will be expanded with leading
0283: * zeros. The default precision is 1. The
0284: * result of converting 0 with an explicit
0285: * precision of 0 is no characters.
0286: * <dt>x<dd> The int argument is converted to unsigned
0287: * hexadecimal format in the style dddd; the
0288: * letters abcdef are used. The precision
0289: * specifies the minimum numberof digits to
0290: * appear; if the value being converted can be
0291: * represented in fewer digits, it will be
0292: * expanded with leading zeros. The default
0293: * precision is 1. The result of converting 0
0294: * with an explicit precision of 0 is no
0295: * characters.
0296: * <dt>X<dd> Behaves the same as the x conversion
0297: * character except that letters ABCDEF are
0298: * used instead of abcdef.
0299: * <dt>f<dd> The floating point number argument is
0300: * written in decimal notation in the style
0301: * [-]ddd.ddd, where the number of digits after
0302: * the radix character (shown here as a decimal
0303: * point) is equal to the precision
0304: * specification. A Locale is used to determine
0305: * the radix character to use in this format.
0306: * If the precision is omitted from the
0307: * argument, six digits are written after the
0308: * radix character; if the precision is
0309: * explicitly 0 and the # flag is not specified,
0310: * no radix character appears. If a radix
0311: * character appears, at least 1 digit appears
0312: * before it. The value is rounded to the
0313: * appropriate number of digits.
0314: * <dt>e,E<dd>The floating point number argument is
0315: * written in the style [-]d.ddde{+-}dd
0316: * (the symbols {+-} indicate either a plus or
0317: * minus sign), where there is one digit before
0318: * the radix character (shown here as a decimal
0319: * point) and the number of digits after it is
0320: * equal to the precision. A Locale is used to
0321: * determine the radix character to use in this
0322: * format. When the precision is missing, six
0323: * digits are written after the radix character;
0324: * if the precision is 0 and the # flag is not
0325: * specified, no radix character appears. The
0326: * E conversion will produce a number with E
0327: * instead of e introducing the exponent. The
0328: * exponent always contains at least two digits.
0329: * However, if the value to be written requires
0330: * an exponent greater than two digits,
0331: * additional exponent digits are written as
0332: * necessary. The value is rounded to the
0333: * appropriate number of digits.
0334: * <dt>g,G<dd>The floating point number argument is
0335: * written in style f or e (or in sytle E in the
0336: * case of a G conversion character), with the
0337: * precision specifying the number of
0338: * significant digits. If the precision is
0339: * zero, it is taken as one. The style used
0340: * depends on the value converted: style e
0341: * (or E) will be used only if the exponent
0342: * resulting from the conversion is less than
0343: * -4 or greater than or equal to the precision.
0344: * Trailing zeros are removed from the result.
0345: * A radix character appears only if it is
0346: * followed by a digit.
0347: * <dt>c,C<dd>The integer argument is converted to a
0348: * char and the result is written.
0349: *
0350: * <dt>s,S<dd>The argument is taken to be a string and
0351: * bytes from the string are written until the
0352: * end of the string or the number of bytes
0353: * indicated by the precision specification of
0354: * the argument is reached. If the precision
0355: * is omitted from the argument, it is taken to
0356: * be infinite, so all characters up to the end
0357: * of the string are written.
0358: * <dt>%<dd>Write a % character; no argument is
0359: * converted.
0360: *</dl>
0361: *<p>
0362: * If a conversion specification does not match one of
0363: * the above forms, an IllegalArgumentException is
0364: * thrown and the instance of PrintfFormat is not
0365: * created.</p>
0366: *<p>
0367: * If a floating point value is the internal
0368: * representation for infinity, the output is
0369: * [+]Infinity, where Infinity is either Infinity or
0370: * Inf, depending on the desired output string length.
0371: * Printing of the sign follows the rules described
0372: * above.</p>
0373: *<p>
0374: * If a floating point value is the internal
0375: * representation for "not-a-number," the output is
0376: * [+]NaN. Printing of the sign follows the rules
0377: * described above.</p>
0378: *<p>
0379: * In no case does a non-existent or small field width
0380: * cause truncation of a field; if the result of a
0381: * conversion is wider than the field width, the field
0382: * is simply expanded to contain the conversion result.
0383: *</p>
0384: *<p>
0385: * The behavior is like printf. One exception is that
0386: * the minimum number of exponent digits is 3 instead
0387: * of 2 for e and E formats when the optional L is used
0388: * before the e, E, g, or G conversion character. The
0389: * optional L does not imply conversion to a long long
0390: * double. </p>
0391: * <p>
0392: * The biggest divergence from the C printf
0393: * specification is in the use of 16 bit characters.
0394: * This allows the handling of characters beyond the
0395: * small ASCII character set and allows the utility to
0396: * interoperate correctly with the rest of the Java
0397: * runtime environment.</p>
0398: *<p>
0399: * Omissions from the C printf specification are
0400: * numerous. All the known omissions are present
0401: * because Java never uses bytes to represent
0402: * characters and does not have pointers:</p>
0403: *<ul>
0404: * <li>%c is the same as %C.
0405: * <li>%s is the same as %S.
0406: * <li>u, p, and n conversion characters.
0407: * <li>%ws format.
0408: * <li>h modifier applied to an n conversion character.
0409: * <li>l (ell) modifier applied to the c, n, or s
0410: * conversion characters.
0411: * <li>ll (ell ell) modifier to d, i, o, u, x, or X
0412: * conversion characters.
0413: * <li>ll (ell ell) modifier to an n conversion
0414: * character.
0415: * <li>c, C, d,i,o,u,x, and X conversion characters
0416: * apply to Byte, Character, Short, Integer, Long
0417: * types.
0418: * <li>f, e, E, g, and G conversion characters apply
0419: * to Float and Double types.
0420: * <li>s and S conversion characters apply to String
0421: * types.
0422: * <li>All other reference types can be formatted
0423: * using the s or S conversion characters only.
0424: *</ul>
0425: * <p>
0426: * Most of this specification is quoted from the Unix
0427: * man page for the sprintf utility.</p>
0428: *
0429: * @author Allan Jacobs
0430: * @version 1
0431: * Release 1: Initial release.
0432: * Release 2: Asterisk field widths and precisions
0433: * %n$ and *m$
0434: * Bug fixes
0435: * g format fix (2 digits in e form corrupt)
0436: * rounding in f format implemented
0437: * round up when digit not printed is 5
0438: * formatting of -0.0f
0439: * round up/down when last digits are 50000...
0440: */
0441: /*public*/class PrintfFormat {
0442: /**
0443: * Constructs an array of control specifications
0444: * possibly preceded, separated, or followed by
0445: * ordinary strings. Control strings begin with
0446: * unpaired percent signs. A pair of successive
0447: * percent signs designates a single percent sign in
0448: * the format.
0449: * @param fmtArg Control string.
0450: * @exception IllegalArgumentException if the control
0451: * string is null, zero length, or otherwise
0452: * malformed.
0453: */
0454: public PrintfFormat(String fmtArg) throws IllegalArgumentException {
0455: this (Locale.getDefault(), fmtArg);
0456: }
0457:
0458: /**
0459: * Constructs an array of control specifications
0460: * possibly preceded, separated, or followed by
0461: * ordinary strings. Control strings begin with
0462: * unpaired percent signs. A pair of successive
0463: * percent signs designates a single percent sign in
0464: * the format.
0465: * @param fmtArg Control string.
0466: * @exception IllegalArgumentException if the control
0467: * string is null, zero length, or otherwise
0468: * malformed.
0469: */
0470: public PrintfFormat(Locale locale, String fmtArg)
0471: throws IllegalArgumentException {
0472: dfs = new DecimalFormatSymbols(locale);
0473: int ePos = 0;
0474: ConversionSpecification sFmt = null;
0475: String unCS = this .nonControl(fmtArg, 0);
0476: if (unCS != null) {
0477: sFmt = new ConversionSpecification();
0478: sFmt.setLiteral(unCS);
0479: vFmt.addElement(sFmt);
0480: }
0481: while (cPos != -1 && cPos < fmtArg.length()) {
0482: for (ePos = cPos + 1; ePos < fmtArg.length(); ePos++) {
0483: char c = 0;
0484: c = fmtArg.charAt(ePos);
0485: if (c == 'i')
0486: break;
0487: if (c == 'd')
0488: break;
0489: if (c == 'f')
0490: break;
0491: if (c == 'g')
0492: break;
0493: if (c == 'G')
0494: break;
0495: if (c == 'o')
0496: break;
0497: if (c == 'x')
0498: break;
0499: if (c == 'X')
0500: break;
0501: if (c == 'e')
0502: break;
0503: if (c == 'E')
0504: break;
0505: if (c == 'c')
0506: break;
0507: if (c == 's')
0508: break;
0509: if (c == '%')
0510: break;
0511: }
0512: ePos = Math.min(ePos + 1, fmtArg.length());
0513: sFmt = new ConversionSpecification(fmtArg.substring(cPos,
0514: ePos));
0515: vFmt.addElement(sFmt);
0516: unCS = this .nonControl(fmtArg, ePos);
0517: if (unCS != null) {
0518: sFmt = new ConversionSpecification();
0519: sFmt.setLiteral(unCS);
0520: vFmt.addElement(sFmt);
0521: }
0522: }
0523: }
0524:
0525: /**
0526: * Return a substring starting at
0527: * <code>start</code> and ending at either the end
0528: * of the String <code>s</code>, the next unpaired
0529: * percent sign, or at the end of the String if the
0530: * last character is a percent sign.
0531: * @param s Control string.
0532: * @param start Position in the string
0533: * <code>s</code> to begin looking for the start
0534: * of a control string.
0535: * @return the substring from the start position
0536: * to the beginning of the control string.
0537: */
0538: private String nonControl(String s, int start) {
0539: String ret = "";
0540: cPos = s.indexOf("%", start);
0541: if (cPos == -1)
0542: cPos = s.length();
0543: return s.substring(start, cPos);
0544: }
0545:
0546: /**
0547: * Format an array of objects. Byte, Short,
0548: * Integer, Long, Float, Double, and Character
0549: * arguments are treated as wrappers for primitive
0550: * types.
0551: * @param o The array of objects to format.
0552: * @return The formatted String.
0553: */
0554: public String sprintf(Object[] o) {
0555: Enumeration e = vFmt.elements();
0556: ConversionSpecification cs = null;
0557: char c = 0;
0558: int i = 0;
0559: StringBuffer sb = new StringBuffer();
0560: while (e.hasMoreElements()) {
0561: cs = (ConversionSpecification) e.nextElement();
0562: c = cs.getConversionCharacter();
0563: if (c == '\0')
0564: sb.append(cs.getLiteral());
0565: else if (c == '%')
0566: sb.append("%");
0567: else {
0568: if (cs.isPositionalSpecification()) {
0569: i = cs.getArgumentPosition() - 1;
0570: if (cs.isPositionalFieldWidth()) {
0571: int ifw = cs.getArgumentPositionForFieldWidth() - 1;
0572: cs.setFieldWidthWithArg(((Integer) o[ifw])
0573: .intValue());
0574: }
0575: if (cs.isPositionalPrecision()) {
0576: int ipr = cs.getArgumentPositionForPrecision() - 1;
0577: cs.setPrecisionWithArg(((Integer) o[ipr])
0578: .intValue());
0579: }
0580: } else {
0581: if (cs.isVariableFieldWidth()) {
0582: cs.setFieldWidthWithArg(((Integer) o[i])
0583: .intValue());
0584: i++;
0585: }
0586: if (cs.isVariablePrecision()) {
0587: cs.setPrecisionWithArg(((Integer) o[i])
0588: .intValue());
0589: i++;
0590: }
0591: }
0592: if (o[i] instanceof Byte)
0593: sb.append(cs.internalsprintf(((Byte) o[i])
0594: .byteValue()));
0595: else if (o[i] instanceof Short)
0596: sb.append(cs.internalsprintf(((Short) o[i])
0597: .shortValue()));
0598: else if (o[i] instanceof Integer)
0599: sb.append(cs.internalsprintf(((Integer) o[i])
0600: .intValue()));
0601: else if (o[i] instanceof Long)
0602: sb.append(cs.internalsprintf(((Long) o[i])
0603: .longValue()));
0604: else if (o[i] instanceof Float)
0605: sb.append(cs.internalsprintf(((Float) o[i])
0606: .floatValue()));
0607: else if (o[i] instanceof Double)
0608: sb.append(cs.internalsprintf(((Double) o[i])
0609: .doubleValue()));
0610: else if (o[i] instanceof Character)
0611: sb.append(cs.internalsprintf(((Character) o[i])
0612: .charValue()));
0613: else if (o[i] instanceof String)
0614: sb.append(cs.internalsprintf((String) o[i]));
0615: else
0616: sb.append(cs.internalsprintf(o[i]));
0617: if (!cs.isPositionalSpecification())
0618: i++;
0619: }
0620: }
0621: return sb.toString();
0622: }
0623:
0624: /**
0625: * Format nothing. Just use the control string.
0626: * @return the formatted String.
0627: */
0628: public String sprintf() {
0629: Enumeration e = vFmt.elements();
0630: ConversionSpecification cs = null;
0631: char c = 0;
0632: StringBuffer sb = new StringBuffer();
0633: while (e.hasMoreElements()) {
0634: cs = (ConversionSpecification) e.nextElement();
0635: c = cs.getConversionCharacter();
0636: if (c == '\0')
0637: sb.append(cs.getLiteral());
0638: else if (c == '%')
0639: sb.append("%");
0640: }
0641: return sb.toString();
0642: }
0643:
0644: /**
0645: * Format an int.
0646: * @param x The int to format.
0647: * @return The formatted String.
0648: * @exception IllegalArgumentException if the
0649: * conversion character is f, e, E, g, G, s,
0650: * or S.
0651: */
0652: public String sprintf(int x) throws IllegalArgumentException {
0653: Enumeration e = vFmt.elements();
0654: ConversionSpecification cs = null;
0655: char c = 0;
0656: StringBuffer sb = new StringBuffer();
0657: while (e.hasMoreElements()) {
0658: cs = (ConversionSpecification) e.nextElement();
0659: c = cs.getConversionCharacter();
0660: if (c == '\0')
0661: sb.append(cs.getLiteral());
0662: else if (c == '%')
0663: sb.append("%");
0664: else
0665: sb.append(cs.internalsprintf(x));
0666: }
0667: return sb.toString();
0668: }
0669:
0670: /**
0671: * Format an long.
0672: * @param x The long to format.
0673: * @return The formatted String.
0674: * @exception IllegalArgumentException if the
0675: * conversion character is f, e, E, g, G, s,
0676: * or S.
0677: */
0678: public String sprintf(long x) throws IllegalArgumentException {
0679: Enumeration e = vFmt.elements();
0680: ConversionSpecification cs = null;
0681: char c = 0;
0682: StringBuffer sb = new StringBuffer();
0683: while (e.hasMoreElements()) {
0684: cs = (ConversionSpecification) e.nextElement();
0685: c = cs.getConversionCharacter();
0686: if (c == '\0')
0687: sb.append(cs.getLiteral());
0688: else if (c == '%')
0689: sb.append("%");
0690: else
0691: sb.append(cs.internalsprintf(x));
0692: }
0693: return sb.toString();
0694: }
0695:
0696: /**
0697: * Format a double.
0698: * @param x The double to format.
0699: * @return The formatted String.
0700: * @exception IllegalArgumentException if the
0701: * conversion character is c, C, s, S,
0702: * d, d, x, X, or o.
0703: */
0704: public String sprintf(double x) throws IllegalArgumentException {
0705: Enumeration e = vFmt.elements();
0706: ConversionSpecification cs = null;
0707: char c = 0;
0708: StringBuffer sb = new StringBuffer();
0709: while (e.hasMoreElements()) {
0710: cs = (ConversionSpecification) e.nextElement();
0711: c = cs.getConversionCharacter();
0712: if (c == '\0')
0713: sb.append(cs.getLiteral());
0714: else if (c == '%')
0715: sb.append("%");
0716: else
0717: sb.append(cs.internalsprintf(x));
0718: }
0719: return sb.toString();
0720: }
0721:
0722: /**
0723: * Format a String.
0724: * @param x The String to format.
0725: * @return The formatted String.
0726: * @exception IllegalArgumentException if the
0727: * conversion character is neither s nor S.
0728: */
0729: public String sprintf(String x) throws IllegalArgumentException {
0730: Enumeration e = vFmt.elements();
0731: ConversionSpecification cs = null;
0732: char c = 0;
0733: StringBuffer sb = new StringBuffer();
0734: while (e.hasMoreElements()) {
0735: cs = (ConversionSpecification) e.nextElement();
0736: c = cs.getConversionCharacter();
0737: if (c == '\0')
0738: sb.append(cs.getLiteral());
0739: else if (c == '%')
0740: sb.append("%");
0741: else
0742: sb.append(cs.internalsprintf(x));
0743: }
0744: return sb.toString();
0745: }
0746:
0747: /**
0748: * Format an Object. Convert wrapper types to
0749: * their primitive equivalents and call the
0750: * appropriate internal formatting method. Convert
0751: * Strings using an internal formatting method for
0752: * Strings. Otherwise use the default formatter
0753: * (use toString).
0754: * @param x the Object to format.
0755: * @return the formatted String.
0756: * @exception IllegalArgumentException if the
0757: * conversion character is inappropriate for
0758: * formatting an unwrapped value.
0759: */
0760: public String sprintf(Object x) throws IllegalArgumentException {
0761: Enumeration e = vFmt.elements();
0762: ConversionSpecification cs = null;
0763: char c = 0;
0764: StringBuffer sb = new StringBuffer();
0765: while (e.hasMoreElements()) {
0766: cs = (ConversionSpecification) e.nextElement();
0767: c = cs.getConversionCharacter();
0768: if (c == '\0')
0769: sb.append(cs.getLiteral());
0770: else if (c == '%')
0771: sb.append("%");
0772: else {
0773: if (x instanceof Byte)
0774: sb.append(cs
0775: .internalsprintf(((Byte) x).byteValue()));
0776: else if (x instanceof Short)
0777: sb.append(cs.internalsprintf(((Short) x)
0778: .shortValue()));
0779: else if (x instanceof Integer)
0780: sb.append(cs.internalsprintf(((Integer) x)
0781: .intValue()));
0782: else if (x instanceof Long)
0783: sb.append(cs
0784: .internalsprintf(((Long) x).longValue()));
0785: else if (x instanceof Float)
0786: sb.append(cs.internalsprintf(((Float) x)
0787: .floatValue()));
0788: else if (x instanceof Double)
0789: sb.append(cs.internalsprintf(((Double) x)
0790: .doubleValue()));
0791: else if (x instanceof Character)
0792: sb.append(cs.internalsprintf(((Character) x)
0793: .charValue()));
0794: else if (x instanceof String)
0795: sb.append(cs.internalsprintf((String) x));
0796: else
0797: sb.append(cs.internalsprintf(x));
0798: }
0799: }
0800: return sb.toString();
0801: }
0802:
0803: /**
0804: *<p>
0805: * ConversionSpecification allows the formatting of
0806: * a single primitive or object embedded within a
0807: * string. The formatting is controlled by a
0808: * format string. Only one Java primitive or
0809: * object can be formatted at a time.
0810: *<p>
0811: * A format string is a Java string that contains
0812: * a control string. The control string starts at
0813: * the first percent sign (%) in the string,
0814: * provided that this percent sign
0815: *<ol>
0816: *<li>is not escaped protected by a matching % or
0817: * is not an escape % character,
0818: *<li>is not at the end of the format string, and
0819: *<li>precedes a sequence of characters that parses
0820: * as a valid control string.
0821: *</ol>
0822: *<p>
0823: * A control string takes the form:
0824: *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
0825: * { [hlL] }+ [idfgGoxXeEcs]
0826: *</pre>
0827: *<p>
0828: * The behavior is like printf. One (hopefully the
0829: * only) exception is that the minimum number of
0830: * exponent digits is 3 instead of 2 for e and E
0831: * formats when the optional L is used before the
0832: * e, E, g, or G conversion character. The
0833: * optional L does not imply conversion to a long
0834: * long double.
0835: */
0836: private class ConversionSpecification {
0837: /**
0838: * Constructor. Used to prepare an instance
0839: * to hold a literal, not a control string.
0840: */
0841: ConversionSpecification() {
0842: }
0843:
0844: /**
0845: * Constructor for a conversion specification.
0846: * The argument must begin with a % and end
0847: * with the conversion character for the
0848: * conversion specification.
0849: * @param fmtArg String specifying the
0850: * conversion specification.
0851: * @exception IllegalArgumentException if the
0852: * input string is null, zero length, or
0853: * otherwise malformed.
0854: */
0855: ConversionSpecification(String fmtArg)
0856: throws IllegalArgumentException {
0857: if (fmtArg == null)
0858: throw new NullPointerException();
0859: if (fmtArg.length() == 0)
0860: throw new IllegalArgumentException(
0861: "Control strings must have positive"
0862: + " lengths.");
0863: if (fmtArg.charAt(0) == '%') {
0864: fmt = fmtArg;
0865: pos = 1;
0866: setArgPosition();
0867: setFlagCharacters();
0868: setFieldWidth();
0869: setPrecision();
0870: setOptionalHL();
0871: if (setConversionCharacter()) {
0872: if (pos == fmtArg.length()) {
0873: if (leadingZeros && leftJustify)
0874: leadingZeros = false;
0875: if (precisionSet && leadingZeros) {
0876: if (conversionCharacter == 'd'
0877: || conversionCharacter == 'i'
0878: || conversionCharacter == 'o'
0879: || conversionCharacter == 'x') {
0880: leadingZeros = false;
0881: }
0882: }
0883: } else
0884: throw new IllegalArgumentException(
0885: "Malformed conversion specification="
0886: + fmtArg);
0887: } else
0888: throw new IllegalArgumentException(
0889: "Malformed conversion specification="
0890: + fmtArg);
0891: } else
0892: throw new IllegalArgumentException(
0893: "Control strings must begin with %.");
0894: }
0895:
0896: /**
0897: * Set the String for this instance.
0898: * @param s the String to store.
0899: */
0900: void setLiteral(String s) {
0901: fmt = s;
0902: }
0903:
0904: /**
0905: * Get the String for this instance. Translate
0906: * any escape sequences.
0907: *
0908: * @return s the stored String.
0909: */
0910: String getLiteral() {
0911: StringBuffer sb = new StringBuffer();
0912: int i = 0;
0913: while (i < fmt.length()) {
0914: if (fmt.charAt(i) == '\\') {
0915: i++;
0916: if (i < fmt.length()) {
0917: char c = fmt.charAt(i);
0918: switch (c) {
0919: case 'a':
0920: sb.append((char) 0x07);
0921: break;
0922: case 'b':
0923: sb.append('\b');
0924: break;
0925: case 'f':
0926: sb.append('\f');
0927: break;
0928: case 'n':
0929: sb.append(System
0930: .getProperty("line.separator"));
0931: break;
0932: case 'r':
0933: sb.append('\r');
0934: break;
0935: case 't':
0936: sb.append('\t');
0937: break;
0938: case 'v':
0939: sb.append((char) 0x0b);
0940: break;
0941: case '\\':
0942: sb.append('\\');
0943: break;
0944: }
0945: i++;
0946: } else
0947: sb.append('\\');
0948: } else
0949: i++;
0950: }
0951: return fmt;
0952: }
0953:
0954: /**
0955: * Get the conversion character that tells what
0956: * type of control character this instance has.
0957: *
0958: * @return the conversion character.
0959: */
0960: char getConversionCharacter() {
0961: return conversionCharacter;
0962: }
0963:
0964: /**
0965: * Check whether the specifier has a variable
0966: * field width that is going to be set by an
0967: * argument.
0968: * @return <code>true</code> if the conversion
0969: * uses an * field width; otherwise
0970: * <code>false</code>.
0971: */
0972: boolean isVariableFieldWidth() {
0973: return variableFieldWidth;
0974: }
0975:
0976: /**
0977: * Set the field width with an argument. A
0978: * negative field width is taken as a - flag
0979: * followed by a positive field width.
0980: * @param fw the field width.
0981: */
0982: void setFieldWidthWithArg(int fw) {
0983: if (fw < 0)
0984: leftJustify = true;
0985: fieldWidthSet = true;
0986: fieldWidth = Math.abs(fw);
0987: }
0988:
0989: /**
0990: * Check whether the specifier has a variable
0991: * precision that is going to be set by an
0992: * argument.
0993: * @return <code>true</code> if the conversion
0994: * uses an * precision; otherwise
0995: * <code>false</code>.
0996: */
0997: boolean isVariablePrecision() {
0998: return variablePrecision;
0999: }
1000:
1001: /**
1002: * Set the precision with an argument. A
1003: * negative precision will be changed to zero.
1004: * @param pr the precision.
1005: */
1006: void setPrecisionWithArg(int pr) {
1007: precisionSet = true;
1008: precision = Math.max(pr, 0);
1009: }
1010:
1011: /**
1012: * Format an int argument using this conversion
1013: * specification.
1014: * @param s the int to format.
1015: * @return the formatted String.
1016: * @exception IllegalArgumentException if the
1017: * conversion character is f, e, E, g, or G.
1018: */
1019: String internalsprintf(int s) throws IllegalArgumentException {
1020: String s2 = "";
1021: switch (conversionCharacter) {
1022: case 'd':
1023: case 'i':
1024: if (optionalh)
1025: s2 = printDFormat((short) s);
1026: else if (optionall)
1027: s2 = printDFormat((long) s);
1028: else
1029: s2 = printDFormat(s);
1030: break;
1031: case 'x':
1032: case 'X':
1033: if (optionalh)
1034: s2 = printXFormat((short) s);
1035: else if (optionall)
1036: s2 = printXFormat((long) s);
1037: else
1038: s2 = printXFormat(s);
1039: break;
1040: case 'o':
1041: if (optionalh)
1042: s2 = printOFormat((short) s);
1043: else if (optionall)
1044: s2 = printOFormat((long) s);
1045: else
1046: s2 = printOFormat(s);
1047: break;
1048: case 'c':
1049: case 'C':
1050: s2 = printCFormat((char) s);
1051: break;
1052: default:
1053: throw new IllegalArgumentException(
1054: "Cannot format a int with a format using a "
1055: + conversionCharacter
1056: + " conversion character.");
1057: }
1058: return s2;
1059: }
1060:
1061: /**
1062: * Format a long argument using this conversion
1063: * specification.
1064: * @param s the long to format.
1065: * @return the formatted String.
1066: * @exception IllegalArgumentException if the
1067: * conversion character is f, e, E, g, or G.
1068: */
1069: String internalsprintf(long s) throws IllegalArgumentException {
1070: String s2 = "";
1071: switch (conversionCharacter) {
1072: case 'd':
1073: case 'i':
1074: if (optionalh)
1075: s2 = printDFormat((short) s);
1076: else if (optionall)
1077: s2 = printDFormat(s);
1078: else
1079: s2 = printDFormat((int) s);
1080: break;
1081: case 'x':
1082: case 'X':
1083: if (optionalh)
1084: s2 = printXFormat((short) s);
1085: else if (optionall)
1086: s2 = printXFormat(s);
1087: else
1088: s2 = printXFormat((int) s);
1089: break;
1090: case 'o':
1091: if (optionalh)
1092: s2 = printOFormat((short) s);
1093: else if (optionall)
1094: s2 = printOFormat(s);
1095: else
1096: s2 = printOFormat((int) s);
1097: break;
1098: case 'c':
1099: case 'C':
1100: s2 = printCFormat((char) s);
1101: break;
1102: default:
1103: throw new IllegalArgumentException(
1104: "Cannot format a long with a format using a "
1105: + conversionCharacter
1106: + " conversion character.");
1107: }
1108: return s2;
1109: }
1110:
1111: /**
1112: * Format a double argument using this conversion
1113: * specification.
1114: * @param s the double to format.
1115: * @return the formatted String.
1116: * @exception IllegalArgumentException if the
1117: * conversion character is c, C, s, S, i, d,
1118: * x, X, or o.
1119: */
1120: String internalsprintf(double s)
1121: throws IllegalArgumentException {
1122: String s2 = "";
1123: switch (conversionCharacter) {
1124: case 'f':
1125: s2 = printFFormat(s);
1126: break;
1127: case 'E':
1128: case 'e':
1129: s2 = printEFormat(s);
1130: break;
1131: case 'G':
1132: case 'g':
1133: s2 = printGFormat(s);
1134: break;
1135: default:
1136: throw new IllegalArgumentException("Cannot "
1137: + "format a double with a format using a "
1138: + conversionCharacter
1139: + " conversion character.");
1140: }
1141: return s2;
1142: }
1143:
1144: /**
1145: * Format a String argument using this conversion
1146: * specification.
1147: * @param s the String to format.
1148: * @return the formatted String.
1149: * @exception IllegalArgumentException if the
1150: * conversion character is neither s nor S.
1151: */
1152: String internalsprintf(String s)
1153: throws IllegalArgumentException {
1154: String s2 = "";
1155: if (conversionCharacter == 's'
1156: || conversionCharacter == 'S')
1157: s2 = printSFormat(s);
1158: else
1159: throw new IllegalArgumentException("Cannot "
1160: + "format a String with a format using a "
1161: + conversionCharacter
1162: + " conversion character.");
1163: return s2;
1164: }
1165:
1166: /**
1167: * Format an Object argument using this conversion
1168: * specification.
1169: * @param s the Object to format.
1170: * @return the formatted String.
1171: * @exception IllegalArgumentException if the
1172: * conversion character is neither s nor S.
1173: */
1174: String internalsprintf(Object s) {
1175: String s2 = "";
1176: if (conversionCharacter == 's'
1177: || conversionCharacter == 'S')
1178: s2 = printSFormat(s.toString());
1179: else
1180: throw new IllegalArgumentException(
1181: "Cannot format a String with a format using"
1182: + " a " + conversionCharacter
1183: + " conversion character.");
1184: return s2;
1185: }
1186:
1187: /**
1188: * For f format, the flag character '-', means that
1189: * the output should be left justified within the
1190: * field. The default is to pad with blanks on the
1191: * left. '+' character means that the conversion
1192: * will always begin with a sign (+ or -). The
1193: * blank flag character means that a non-negative
1194: * input will be preceded with a blank. If both
1195: * a '+' and a ' ' are specified, the blank flag
1196: * is ignored. The '0' flag character implies that
1197: * padding to the field width will be done with
1198: * zeros instead of blanks.
1199: *
1200: * The field width is treated as the minimum number
1201: * of characters to be printed. The default is to
1202: * add no padding. Padding is with blanks by
1203: * default.
1204: *
1205: * The precision, if set, is the number of digits
1206: * to appear after the radix character. Padding is
1207: * with trailing 0s.
1208: */
1209: private char[] fFormatDigits(double x) {
1210: // int defaultDigits=6;
1211: String sx, sxOut;
1212: int i, j, k;
1213: int n1In, n2In;
1214: int expon = 0;
1215: boolean minusSign = false;
1216: if (x > 0.0)
1217: sx = Double.toString(x);
1218: else if (x < 0.0) {
1219: sx = Double.toString(-x);
1220: minusSign = true;
1221: } else {
1222: sx = Double.toString(x);
1223: if (sx.charAt(0) == '-') {
1224: minusSign = true;
1225: sx = sx.substring(1);
1226: }
1227: }
1228: int ePos = sx.indexOf('E');
1229: int rPos = sx.indexOf('.');
1230: if (rPos != -1)
1231: n1In = rPos;
1232: else if (ePos != -1)
1233: n1In = ePos;
1234: else
1235: n1In = sx.length();
1236: if (rPos != -1) {
1237: if (ePos != -1)
1238: n2In = ePos - rPos - 1;
1239: else
1240: n2In = sx.length() - rPos - 1;
1241: } else
1242: n2In = 0;
1243: if (ePos != -1) {
1244: int ie = ePos + 1;
1245: expon = 0;
1246: if (sx.charAt(ie) == '-') {
1247: for (++ie; ie < sx.length(); ie++)
1248: if (sx.charAt(ie) != '0')
1249: break;
1250: if (ie < sx.length())
1251: expon = -Integer.parseInt(sx.substring(ie));
1252: } else {
1253: if (sx.charAt(ie) == '+')
1254: ++ie;
1255: for (; ie < sx.length(); ie++)
1256: if (sx.charAt(ie) != '0')
1257: break;
1258: if (ie < sx.length())
1259: expon = Integer.parseInt(sx.substring(ie));
1260: }
1261: }
1262: int p;
1263: if (precisionSet)
1264: p = precision;
1265: else
1266: p = defaultDigits - 1;
1267: char[] ca1 = sx.toCharArray();
1268: char[] ca2 = new char[n1In + n2In];
1269: char[] ca3, ca4, ca5;
1270: for (j = 0; j < n1In; j++)
1271: ca2[j] = ca1[j];
1272: i = j + 1;
1273: for (k = 0; k < n2In; j++, i++, k++)
1274: ca2[j] = ca1[i];
1275: if (n1In + expon <= 0) {
1276: ca3 = new char[-expon + n2In];
1277: for (j = 0, k = 0; k < (-n1In - expon); k++, j++)
1278: ca3[j] = '0';
1279: for (i = 0; i < (n1In + n2In); i++, j++)
1280: ca3[j] = ca2[i];
1281: } else
1282: ca3 = ca2;
1283: boolean carry = false;
1284: if (p < -expon + n2In) {
1285: if (expon < 0)
1286: i = p;
1287: else
1288: i = p + n1In;
1289: carry = checkForCarry(ca3, i);
1290: if (carry)
1291: carry = startSymbolicCarry(ca3, i - 1, 0);
1292: }
1293: if (n1In + expon <= 0) {
1294: ca4 = new char[2 + p];
1295: if (!carry)
1296: ca4[0] = '0';
1297: else
1298: ca4[0] = '1';
1299: if (alternateForm || !precisionSet || precision != 0) {
1300: ca4[1] = '.';
1301: for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
1302: ca4[j] = ca3[i];
1303: for (; j < ca4.length; j++)
1304: ca4[j] = '0';
1305: }
1306: } else {
1307: if (!carry) {
1308: if (alternateForm || !precisionSet
1309: || precision != 0)
1310: ca4 = new char[n1In + expon + p + 1];
1311: else
1312: ca4 = new char[n1In + expon];
1313: j = 0;
1314: } else {
1315: if (alternateForm || !precisionSet
1316: || precision != 0)
1317: ca4 = new char[n1In + expon + p + 2];
1318: else
1319: ca4 = new char[n1In + expon + 1];
1320: ca4[0] = '1';
1321: j = 1;
1322: }
1323: for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
1324: ca4[j] = ca3[i];
1325: for (; i < n1In + expon; i++, j++)
1326: ca4[j] = '0';
1327: if (alternateForm || !precisionSet || precision != 0) {
1328: ca4[j] = '.';
1329: j++;
1330: for (k = 0; i < ca3.length && k < p; i++, j++, k++)
1331: ca4[j] = ca3[i];
1332: for (; j < ca4.length; j++)
1333: ca4[j] = '0';
1334: }
1335: }
1336: int nZeros = 0;
1337: if (!leftJustify && leadingZeros) {
1338: int xThousands = 0;
1339: if (thousands) {
1340: int xlead = 0;
1341: if (ca4[0] == '+' || ca4[0] == '-' || ca4[0] == ' ')
1342: xlead = 1;
1343: int xdp = xlead;
1344: for (; xdp < ca4.length; xdp++)
1345: if (ca4[xdp] == '.')
1346: break;
1347: xThousands = (xdp - xlead) / 3;
1348: }
1349: if (fieldWidthSet)
1350: nZeros = fieldWidth - ca4.length;
1351: if ((!minusSign && (leadingSign || leadingSpace))
1352: || minusSign)
1353: nZeros--;
1354: nZeros -= xThousands;
1355: if (nZeros < 0)
1356: nZeros = 0;
1357: }
1358: j = 0;
1359: if ((!minusSign && (leadingSign || leadingSpace))
1360: || minusSign) {
1361: ca5 = new char[ca4.length + nZeros + 1];
1362: j++;
1363: } else
1364: ca5 = new char[ca4.length + nZeros];
1365: if (!minusSign) {
1366: if (leadingSign)
1367: ca5[0] = '+';
1368: if (leadingSpace)
1369: ca5[0] = ' ';
1370: } else
1371: ca5[0] = '-';
1372: for (i = 0; i < nZeros; i++, j++)
1373: ca5[j] = '0';
1374: for (i = 0; i < ca4.length; i++, j++)
1375: ca5[j] = ca4[i];
1376:
1377: int lead = 0;
1378: if (ca5[0] == '+' || ca5[0] == '-' || ca5[0] == ' ')
1379: lead = 1;
1380: int dp = lead;
1381: for (; dp < ca5.length; dp++)
1382: if (ca5[dp] == '.')
1383: break;
1384: int nThousands = (dp - lead) / 3;
1385: // Localize the decimal point.
1386: if (dp < ca5.length)
1387: ca5[dp] = dfs.getDecimalSeparator();
1388: char[] ca6 = ca5;
1389: if (thousands && nThousands > 0) {
1390: ca6 = new char[ca5.length + nThousands + lead];
1391: ca6[0] = ca5[0];
1392: for (i = lead, k = lead; i < dp; i++) {
1393: if (i > 0 && (dp - i) % 3 == 0) {
1394: // ca6[k]=',';
1395: ca6[k] = dfs.getGroupingSeparator();
1396: ca6[k + 1] = ca5[i];
1397: k += 2;
1398: } else {
1399: ca6[k] = ca5[i];
1400: k++;
1401: }
1402: }
1403: for (; i < ca5.length; i++, k++) {
1404: ca6[k] = ca5[i];
1405: }
1406: }
1407: return ca6;
1408: }
1409:
1410: /**
1411: * An intermediate routine on the way to creating
1412: * an f format String. The method decides whether
1413: * the input double value is an infinity,
1414: * not-a-number, or a finite double and formats
1415: * each type of input appropriately.
1416: * @param x the double value to be formatted.
1417: * @return the converted double value.
1418: */
1419: private String fFormatString(double x) {
1420: boolean noDigits = false;
1421: char[] ca6, ca7;
1422: if (Double.isInfinite(x)) {
1423: if (x == Double.POSITIVE_INFINITY) {
1424: if (leadingSign)
1425: ca6 = "+Inf".toCharArray();
1426: else if (leadingSpace)
1427: ca6 = " Inf".toCharArray();
1428: else
1429: ca6 = "Inf".toCharArray();
1430: } else
1431: ca6 = "-Inf".toCharArray();
1432: noDigits = true;
1433: } else if (Double.isNaN(x)) {
1434: if (leadingSign)
1435: ca6 = "+NaN".toCharArray();
1436: else if (leadingSpace)
1437: ca6 = " NaN".toCharArray();
1438: else
1439: ca6 = "NaN".toCharArray();
1440: noDigits = true;
1441: } else
1442: ca6 = fFormatDigits(x);
1443: ca7 = applyFloatPadding(ca6, false);
1444: return new String(ca7);
1445: }
1446:
1447: /**
1448: * For e format, the flag character '-', means that
1449: * the output should be left justified within the
1450: * field. The default is to pad with blanks on the
1451: * left. '+' character means that the conversion
1452: * will always begin with a sign (+ or -). The
1453: * blank flag character means that a non-negative
1454: * input will be preceded with a blank. If both a
1455: * '+' and a ' ' are specified, the blank flag is
1456: * ignored. The '0' flag character implies that
1457: * padding to the field width will be done with
1458: * zeros instead of blanks.
1459: *
1460: * The field width is treated as the minimum number
1461: * of characters to be printed. The default is to
1462: * add no padding. Padding is with blanks by
1463: * default.
1464: *
1465: * The precision, if set, is the minimum number of
1466: * digits to appear after the radix character.
1467: * Padding is with trailing 0s.
1468: *
1469: * The behavior is like printf. One (hopefully the
1470: * only) exception is that the minimum number of
1471: * exponent digits is 3 instead of 2 for e and E
1472: * formats when the optional L is used before the
1473: * e, E, g, or G conversion character. The optional
1474: * L does not imply conversion to a long long
1475: * double.
1476: */
1477: private char[] eFormatDigits(double x, char eChar) {
1478: char[] ca1, ca2, ca3;
1479: // int defaultDigits=6;
1480: String sx, sxOut;
1481: int i, j, k, p;
1482: int n1In, n2In;
1483: int expon = 0;
1484: int ePos, rPos, eSize;
1485: boolean minusSign = false;
1486: if (x > 0.0)
1487: sx = Double.toString(x);
1488: else if (x < 0.0) {
1489: sx = Double.toString(-x);
1490: minusSign = true;
1491: } else {
1492: sx = Double.toString(x);
1493: if (sx.charAt(0) == '-') {
1494: minusSign = true;
1495: sx = sx.substring(1);
1496: }
1497: }
1498: ePos = sx.indexOf('E');
1499: if (ePos == -1)
1500: ePos = sx.indexOf('e');
1501: rPos = sx.indexOf('.');
1502: if (rPos != -1)
1503: n1In = rPos;
1504: else if (ePos != -1)
1505: n1In = ePos;
1506: else
1507: n1In = sx.length();
1508: if (rPos != -1) {
1509: if (ePos != -1)
1510: n2In = ePos - rPos - 1;
1511: else
1512: n2In = sx.length() - rPos - 1;
1513: } else
1514: n2In = 0;
1515: if (ePos != -1) {
1516: int ie = ePos + 1;
1517: expon = 0;
1518: if (sx.charAt(ie) == '-') {
1519: for (++ie; ie < sx.length(); ie++)
1520: if (sx.charAt(ie) != '0')
1521: break;
1522: if (ie < sx.length())
1523: expon = -Integer.parseInt(sx.substring(ie));
1524: } else {
1525: if (sx.charAt(ie) == '+')
1526: ++ie;
1527: for (; ie < sx.length(); ie++)
1528: if (sx.charAt(ie) != '0')
1529: break;
1530: if (ie < sx.length())
1531: expon = Integer.parseInt(sx.substring(ie));
1532: }
1533: }
1534: if (rPos != -1)
1535: expon += rPos - 1;
1536: if (precisionSet)
1537: p = precision;
1538: else
1539: p = defaultDigits - 1;
1540: if (rPos != -1 && ePos != -1)
1541: ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1,
1542: ePos)).toCharArray();
1543: else if (rPos != -1)
1544: ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1))
1545: .toCharArray();
1546: else if (ePos != -1)
1547: ca1 = sx.substring(0, ePos).toCharArray();
1548: else
1549: ca1 = sx.toCharArray();
1550: boolean carry = false;
1551: int i0 = 0;
1552: if (ca1[0] != '0')
1553: i0 = 0;
1554: else
1555: for (i0 = 0; i0 < ca1.length; i0++)
1556: if (ca1[i0] != '0')
1557: break;
1558: if (i0 + p < ca1.length - 1) {
1559: carry = checkForCarry(ca1, i0 + p + 1);
1560: if (carry)
1561: carry = startSymbolicCarry(ca1, i0 + p, i0);
1562: if (carry) {
1563: ca2 = new char[i0 + p + 1];
1564: ca2[i0] = '1';
1565: for (j = 0; j < i0; j++)
1566: ca2[j] = '0';
1567: for (i = i0, j = i0 + 1; j < p + 1; i++, j++)
1568: ca2[j] = ca1[i];
1569: expon++;
1570: ca1 = ca2;
1571: }
1572: }
1573: if (Math.abs(expon) < 100 && !optionalL)
1574: eSize = 4;
1575: else
1576: eSize = 5;
1577: if (alternateForm || !precisionSet || precision != 0)
1578: ca2 = new char[2 + p + eSize];
1579: else
1580: ca2 = new char[1 + eSize];
1581: if (ca1[0] != '0') {
1582: ca2[0] = ca1[0];
1583: j = 1;
1584: } else {
1585: for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++)
1586: if (ca1[j] != '0')
1587: break;
1588: if ((ePos != -1 && j < ePos)
1589: || (ePos == -1 && j < ca1.length)) {
1590: ca2[0] = ca1[j];
1591: expon -= j;
1592: j++;
1593: } else {
1594: ca2[0] = '0';
1595: j = 2;
1596: }
1597: }
1598: if (alternateForm || !precisionSet || precision != 0) {
1599: ca2[1] = '.';
1600: i = 2;
1601: } else
1602: i = 1;
1603: for (k = 0; k < p && j < ca1.length; j++, i++, k++)
1604: ca2[i] = ca1[j];
1605: for (; i < ca2.length - eSize; i++)
1606: ca2[i] = '0';
1607: ca2[i++] = eChar;
1608: if (expon < 0)
1609: ca2[i++] = '-';
1610: else
1611: ca2[i++] = '+';
1612: expon = Math.abs(expon);
1613: if (expon >= 100) {
1614: switch (expon / 100) {
1615: case 1:
1616: ca2[i] = '1';
1617: break;
1618: case 2:
1619: ca2[i] = '2';
1620: break;
1621: case 3:
1622: ca2[i] = '3';
1623: break;
1624: case 4:
1625: ca2[i] = '4';
1626: break;
1627: case 5:
1628: ca2[i] = '5';
1629: break;
1630: case 6:
1631: ca2[i] = '6';
1632: break;
1633: case 7:
1634: ca2[i] = '7';
1635: break;
1636: case 8:
1637: ca2[i] = '8';
1638: break;
1639: case 9:
1640: ca2[i] = '9';
1641: break;
1642: }
1643: i++;
1644: }
1645: switch ((expon % 100) / 10) {
1646: case 0:
1647: ca2[i] = '0';
1648: break;
1649: case 1:
1650: ca2[i] = '1';
1651: break;
1652: case 2:
1653: ca2[i] = '2';
1654: break;
1655: case 3:
1656: ca2[i] = '3';
1657: break;
1658: case 4:
1659: ca2[i] = '4';
1660: break;
1661: case 5:
1662: ca2[i] = '5';
1663: break;
1664: case 6:
1665: ca2[i] = '6';
1666: break;
1667: case 7:
1668: ca2[i] = '7';
1669: break;
1670: case 8:
1671: ca2[i] = '8';
1672: break;
1673: case 9:
1674: ca2[i] = '9';
1675: break;
1676: }
1677: i++;
1678: switch (expon % 10) {
1679: case 0:
1680: ca2[i] = '0';
1681: break;
1682: case 1:
1683: ca2[i] = '1';
1684: break;
1685: case 2:
1686: ca2[i] = '2';
1687: break;
1688: case 3:
1689: ca2[i] = '3';
1690: break;
1691: case 4:
1692: ca2[i] = '4';
1693: break;
1694: case 5:
1695: ca2[i] = '5';
1696: break;
1697: case 6:
1698: ca2[i] = '6';
1699: break;
1700: case 7:
1701: ca2[i] = '7';
1702: break;
1703: case 8:
1704: ca2[i] = '8';
1705: break;
1706: case 9:
1707: ca2[i] = '9';
1708: break;
1709: }
1710: int nZeros = 0;
1711: if (!leftJustify && leadingZeros) {
1712: int xThousands = 0;
1713: if (thousands) {
1714: int xlead = 0;
1715: if (ca2[0] == '+' || ca2[0] == '-' || ca2[0] == ' ')
1716: xlead = 1;
1717: int xdp = xlead;
1718: for (; xdp < ca2.length; xdp++)
1719: if (ca2[xdp] == '.')
1720: break;
1721: xThousands = (xdp - xlead) / 3;
1722: }
1723: if (fieldWidthSet)
1724: nZeros = fieldWidth - ca2.length;
1725: if ((!minusSign && (leadingSign || leadingSpace))
1726: || minusSign)
1727: nZeros--;
1728: nZeros -= xThousands;
1729: if (nZeros < 0)
1730: nZeros = 0;
1731: }
1732: j = 0;
1733: if ((!minusSign && (leadingSign || leadingSpace))
1734: || minusSign) {
1735: ca3 = new char[ca2.length + nZeros + 1];
1736: j++;
1737: } else
1738: ca3 = new char[ca2.length + nZeros];
1739: if (!minusSign) {
1740: if (leadingSign)
1741: ca3[0] = '+';
1742: if (leadingSpace)
1743: ca3[0] = ' ';
1744: } else
1745: ca3[0] = '-';
1746: for (k = 0; k < nZeros; j++, k++)
1747: ca3[j] = '0';
1748: for (i = 0; i < ca2.length && j < ca3.length; i++, j++)
1749: ca3[j] = ca2[i];
1750:
1751: int lead = 0;
1752: if (ca3[0] == '+' || ca3[0] == '-' || ca3[0] == ' ')
1753: lead = 1;
1754: int dp = lead;
1755: for (; dp < ca3.length; dp++)
1756: if (ca3[dp] == '.')
1757: break;
1758: int nThousands = dp / 3;
1759: // Localize the decimal point.
1760: if (dp < ca3.length)
1761: ca3[dp] = dfs.getDecimalSeparator();
1762: char[] ca4 = ca3;
1763: if (thousands && nThousands > 0) {
1764: ca4 = new char[ca3.length + nThousands + lead];
1765: ca4[0] = ca3[0];
1766: for (i = lead, k = lead; i < dp; i++) {
1767: if (i > 0 && (dp - i) % 3 == 0) {
1768: // ca4[k]=',';
1769: ca4[k] = dfs.getGroupingSeparator();
1770: ca4[k + 1] = ca3[i];
1771: k += 2;
1772: } else {
1773: ca4[k] = ca3[i];
1774: k++;
1775: }
1776: }
1777: for (; i < ca3.length; i++, k++)
1778: ca4[k] = ca3[i];
1779: }
1780: return ca4;
1781: }
1782:
1783: /**
1784: * Check to see if the digits that are going to
1785: * be truncated because of the precision should
1786: * force a round in the preceding digits.
1787: * @param ca1 the array of digits
1788: * @param icarry the index of the first digit that
1789: * is to be truncated from the print
1790: * @return <code>true</code> if the truncation forces
1791: * a round that will change the print
1792: */
1793: private boolean checkForCarry(char[] ca1, int icarry) {
1794: boolean carry = false;
1795: if (icarry < ca1.length) {
1796: if (ca1[icarry] == '6' || ca1[icarry] == '7'
1797: || ca1[icarry] == '8' || ca1[icarry] == '9')
1798: carry = true;
1799: else if (ca1[icarry] == '5') {
1800: int ii = icarry + 1;
1801: for (; ii < ca1.length; ii++)
1802: if (ca1[ii] != '0')
1803: break;
1804: carry = ii < ca1.length;
1805: if (!carry && icarry > 0) {
1806: carry = (ca1[icarry - 1] == '1'
1807: || ca1[icarry - 1] == '3'
1808: || ca1[icarry - 1] == '5'
1809: || ca1[icarry - 1] == '7' || ca1[icarry - 1] == '9');
1810: }
1811: }
1812: }
1813: return carry;
1814: }
1815:
1816: /**
1817: * Start the symbolic carry process. The process
1818: * is not quite finished because the symbolic
1819: * carry may change the length of the string and
1820: * change the exponent (in e format).
1821: * @param cLast index of the last digit changed
1822: * by the round
1823: * @param cFirst index of the first digit allowed
1824: * to be changed by this phase of the round
1825: * @return <code>true</code> if the carry forces
1826: * a round that will change the print still
1827: * more
1828: */
1829: private boolean startSymbolicCarry(char[] ca, int cLast,
1830: int cFirst) {
1831: boolean carry = true;
1832: for (int i = cLast; carry && i >= cFirst; i--) {
1833: carry = false;
1834: switch (ca[i]) {
1835: case '0':
1836: ca[i] = '1';
1837: break;
1838: case '1':
1839: ca[i] = '2';
1840: break;
1841: case '2':
1842: ca[i] = '3';
1843: break;
1844: case '3':
1845: ca[i] = '4';
1846: break;
1847: case '4':
1848: ca[i] = '5';
1849: break;
1850: case '5':
1851: ca[i] = '6';
1852: break;
1853: case '6':
1854: ca[i] = '7';
1855: break;
1856: case '7':
1857: ca[i] = '8';
1858: break;
1859: case '8':
1860: ca[i] = '9';
1861: break;
1862: case '9':
1863: ca[i] = '0';
1864: carry = true;
1865: break;
1866: }
1867: }
1868: return carry;
1869: }
1870:
1871: /**
1872: * An intermediate routine on the way to creating
1873: * an e format String. The method decides whether
1874: * the input double value is an infinity,
1875: * not-a-number, or a finite double and formats
1876: * each type of input appropriately.
1877: * @param x the double value to be formatted.
1878: * @param eChar an 'e' or 'E' to use in the
1879: * converted double value.
1880: * @return the converted double value.
1881: */
1882: private String eFormatString(double x, char eChar) {
1883: boolean noDigits = false;
1884: char[] ca4, ca5;
1885: if (Double.isInfinite(x)) {
1886: if (x == Double.POSITIVE_INFINITY) {
1887: if (leadingSign)
1888: ca4 = "+Inf".toCharArray();
1889: else if (leadingSpace)
1890: ca4 = " Inf".toCharArray();
1891: else
1892: ca4 = "Inf".toCharArray();
1893: } else
1894: ca4 = "-Inf".toCharArray();
1895: noDigits = true;
1896: } else if (Double.isNaN(x)) {
1897: if (leadingSign)
1898: ca4 = "+NaN".toCharArray();
1899: else if (leadingSpace)
1900: ca4 = " NaN".toCharArray();
1901: else
1902: ca4 = "NaN".toCharArray();
1903: noDigits = true;
1904: } else
1905: ca4 = eFormatDigits(x, eChar);
1906: ca5 = applyFloatPadding(ca4, false);
1907: return new String(ca5);
1908: }
1909:
1910: /**
1911: * Apply zero or blank, left or right padding.
1912: * @param ca4 array of characters before padding is
1913: * finished
1914: * @param noDigits NaN or signed Inf
1915: * @return a padded array of characters
1916: */
1917: private char[] applyFloatPadding(char[] ca4, boolean noDigits) {
1918: char[] ca5 = ca4;
1919: if (fieldWidthSet) {
1920: int i, j, nBlanks;
1921: if (leftJustify) {
1922: nBlanks = fieldWidth - ca4.length;
1923: if (nBlanks > 0) {
1924: ca5 = new char[ca4.length + nBlanks];
1925: for (i = 0; i < ca4.length; i++)
1926: ca5[i] = ca4[i];
1927: for (j = 0; j < nBlanks; j++, i++)
1928: ca5[i] = ' ';
1929: }
1930: } else if (!leadingZeros || noDigits) {
1931: nBlanks = fieldWidth - ca4.length;
1932: if (nBlanks > 0) {
1933: ca5 = new char[ca4.length + nBlanks];
1934: for (i = 0; i < nBlanks; i++)
1935: ca5[i] = ' ';
1936: for (j = 0; j < ca4.length; i++, j++)
1937: ca5[i] = ca4[j];
1938: }
1939: } else if (leadingZeros) {
1940: nBlanks = fieldWidth - ca4.length;
1941: if (nBlanks > 0) {
1942: ca5 = new char[ca4.length + nBlanks];
1943: i = 0;
1944: j = 0;
1945: if (ca4[0] == '-') {
1946: ca5[0] = '-';
1947: i++;
1948: j++;
1949: }
1950: for (int k = 0; k < nBlanks; i++, k++)
1951: ca5[i] = '0';
1952: for (; j < ca4.length; i++, j++)
1953: ca5[i] = ca4[j];
1954: }
1955: }
1956: }
1957: return ca5;
1958: }
1959:
1960: /**
1961: * Format method for the f conversion character.
1962: * @param x the double to format.
1963: * @return the formatted String.
1964: */
1965: private String printFFormat(double x) {
1966: return fFormatString(x);
1967: }
1968:
1969: /**
1970: * Format method for the e or E conversion
1971: * character.
1972: * @param x the double to format.
1973: * @return the formatted String.
1974: */
1975: private String printEFormat(double x) {
1976: if (conversionCharacter == 'e')
1977: return eFormatString(x, 'e');
1978: else
1979: return eFormatString(x, 'E');
1980: }
1981:
1982: /**
1983: * Format method for the g conversion character.
1984: *
1985: * For g format, the flag character '-', means that
1986: * the output should be left justified within the
1987: * field. The default is to pad with blanks on the
1988: * left. '+' character means that the conversion
1989: * will always begin with a sign (+ or -). The
1990: * blank flag character means that a non-negative
1991: * input will be preceded with a blank. If both a
1992: * '+' and a ' ' are specified, the blank flag is
1993: * ignored. The '0' flag character implies that
1994: * padding to the field width will be done with
1995: * zeros instead of blanks.
1996: *
1997: * The field width is treated as the minimum number
1998: * of characters to be printed. The default is to
1999: * add no padding. Padding is with blanks by
2000: * default.
2001: *
2002: * The precision, if set, is the minimum number of
2003: * digits to appear after the radix character.
2004: * Padding is with trailing 0s.
2005: * @param x the double to format.
2006: * @return the formatted String.
2007: */
2008: private String printGFormat(double x) {
2009: String sx, sy, sz, ret;
2010: int savePrecision = precision;
2011: int i;
2012: char[] ca4, ca5;
2013: boolean noDigits = false;
2014: if (Double.isInfinite(x)) {
2015: if (x == Double.POSITIVE_INFINITY) {
2016: if (leadingSign)
2017: ca4 = "+Inf".toCharArray();
2018: else if (leadingSpace)
2019: ca4 = " Inf".toCharArray();
2020: else
2021: ca4 = "Inf".toCharArray();
2022: } else
2023: ca4 = "-Inf".toCharArray();
2024: noDigits = true;
2025: } else if (Double.isNaN(x)) {
2026: if (leadingSign)
2027: ca4 = "+NaN".toCharArray();
2028: else if (leadingSpace)
2029: ca4 = " NaN".toCharArray();
2030: else
2031: ca4 = "NaN".toCharArray();
2032: noDigits = true;
2033: } else {
2034: if (!precisionSet)
2035: precision = defaultDigits;
2036: if (precision == 0)
2037: precision = 1;
2038: int ePos = -1;
2039: if (conversionCharacter == 'g') {
2040: sx = eFormatString(x, 'e').trim();
2041: ePos = sx.indexOf('e');
2042: } else {
2043: sx = eFormatString(x, 'E').trim();
2044: ePos = sx.indexOf('E');
2045: }
2046: i = ePos + 1;
2047: int expon = 0;
2048: if (sx.charAt(i) == '-') {
2049: for (++i; i < sx.length(); i++)
2050: if (sx.charAt(i) != '0')
2051: break;
2052: if (i < sx.length())
2053: expon = -Integer.parseInt(sx.substring(i));
2054: } else {
2055: if (sx.charAt(i) == '+')
2056: ++i;
2057: for (; i < sx.length(); i++)
2058: if (sx.charAt(i) != '0')
2059: break;
2060: if (i < sx.length())
2061: expon = Integer.parseInt(sx.substring(i));
2062: }
2063: // Trim trailing zeros.
2064: // If the radix character is not followed by
2065: // a digit, trim it, too.
2066: if (!alternateForm) {
2067: if (expon >= -4 && expon < precision)
2068: sy = fFormatString(x).trim();
2069: else
2070: sy = sx.substring(0, ePos);
2071: i = sy.length() - 1;
2072: for (; i >= 0; i--)
2073: if (sy.charAt(i) != '0')
2074: break;
2075: if (i >= 0 && sy.charAt(i) == '.')
2076: i--;
2077: if (i == -1)
2078: sz = "0";
2079: else if (!Character.isDigit(sy.charAt(i)))
2080: sz = sy.substring(0, i + 1) + "0";
2081: else
2082: sz = sy.substring(0, i + 1);
2083: if (expon >= -4 && expon < precision)
2084: ret = sz;
2085: else
2086: ret = sz + sx.substring(ePos);
2087: } else {
2088: if (expon >= -4 && expon < precision)
2089: ret = fFormatString(x).trim();
2090: else
2091: ret = sx;
2092: }
2093: // leading space was trimmed off during
2094: // construction
2095: if (leadingSpace)
2096: if (x >= 0)
2097: ret = " " + ret;
2098: ca4 = ret.toCharArray();
2099: }
2100: // Pad with blanks or zeros.
2101: ca5 = applyFloatPadding(ca4, false);
2102: precision = savePrecision;
2103: return new String(ca5);
2104: }
2105:
2106: /**
2107: * Format method for the d conversion specifer and
2108: * short argument.
2109: *
2110: * For d format, the flag character '-', means that
2111: * the output should be left justified within the
2112: * field. The default is to pad with blanks on the
2113: * left. A '+' character means that the conversion
2114: * will always begin with a sign (+ or -). The
2115: * blank flag character means that a non-negative
2116: * input will be preceded with a blank. If both a
2117: * '+' and a ' ' are specified, the blank flag is
2118: * ignored. The '0' flag character implies that
2119: * padding to the field width will be done with
2120: * zeros instead of blanks.
2121: *
2122: * The field width is treated as the minimum number
2123: * of characters to be printed. The default is to
2124: * add no padding. Padding is with blanks by
2125: * default.
2126: *
2127: * The precision, if set, is the minimum number of
2128: * digits to appear. Padding is with leading 0s.
2129: * @param x the short to format.
2130: * @return the formatted String.
2131: */
2132: private String printDFormat(short x) {
2133: return printDFormat(Short.toString(x));
2134: }
2135:
2136: /**
2137: * Format method for the d conversion character and
2138: * long argument.
2139: *
2140: * For d format, the flag character '-', means that
2141: * the output should be left justified within the
2142: * field. The default is to pad with blanks on the
2143: * left. A '+' character means that the conversion
2144: * will always begin with a sign (+ or -). The
2145: * blank flag character means that a non-negative
2146: * input will be preceded with a blank. If both a
2147: * '+' and a ' ' are specified, the blank flag is
2148: * ignored. The '0' flag character implies that
2149: * padding to the field width will be done with
2150: * zeros instead of blanks.
2151: *
2152: * The field width is treated as the minimum number
2153: * of characters to be printed. The default is to
2154: * add no padding. Padding is with blanks by
2155: * default.
2156: *
2157: * The precision, if set, is the minimum number of
2158: * digits to appear. Padding is with leading 0s.
2159: * @param x the long to format.
2160: * @return the formatted String.
2161: */
2162: private String printDFormat(long x) {
2163: return printDFormat(Long.toString(x));
2164: }
2165:
2166: /**
2167: * Format method for the d conversion character and
2168: * int argument.
2169: *
2170: * For d format, the flag character '-', means that
2171: * the output should be left justified within the
2172: * field. The default is to pad with blanks on the
2173: * left. A '+' character means that the conversion
2174: * will always begin with a sign (+ or -). The
2175: * blank flag character means that a non-negative
2176: * input will be preceded with a blank. If both a
2177: * '+' and a ' ' are specified, the blank flag is
2178: * ignored. The '0' flag character implies that
2179: * padding to the field width will be done with
2180: * zeros instead of blanks.
2181: *
2182: * The field width is treated as the minimum number
2183: * of characters to be printed. The default is to
2184: * add no padding. Padding is with blanks by
2185: * default.
2186: *
2187: * The precision, if set, is the minimum number of
2188: * digits to appear. Padding is with leading 0s.
2189: * @param x the int to format.
2190: * @return the formatted String.
2191: */
2192: private String printDFormat(int x) {
2193: return printDFormat(Integer.toString(x));
2194: }
2195:
2196: /**
2197: * Utility method for formatting using the d
2198: * conversion character.
2199: * @param sx the String to format, the result of
2200: * converting a short, int, or long to a
2201: * String.
2202: * @return the formatted String.
2203: */
2204: private String printDFormat(String sx) {
2205: int nLeadingZeros = 0;
2206: int nBlanks = 0, n = 0;
2207: int i = 0, jFirst = 0;
2208: boolean neg = sx.charAt(0) == '-';
2209: if (sx.equals("0") && precisionSet && precision == 0)
2210: sx = "";
2211: if (!neg) {
2212: if (precisionSet && sx.length() < precision)
2213: nLeadingZeros = precision - sx.length();
2214: } else {
2215: if (precisionSet && (sx.length() - 1) < precision)
2216: nLeadingZeros = precision - sx.length() + 1;
2217: }
2218: if (nLeadingZeros < 0)
2219: nLeadingZeros = 0;
2220: if (fieldWidthSet) {
2221: nBlanks = fieldWidth - nLeadingZeros - sx.length();
2222: if (!neg && (leadingSign || leadingSpace))
2223: nBlanks--;
2224: }
2225: if (nBlanks < 0)
2226: nBlanks = 0;
2227: if (leadingSign)
2228: n++;
2229: else if (leadingSpace)
2230: n++;
2231: n += nBlanks;
2232: n += nLeadingZeros;
2233: n += sx.length();
2234: char[] ca = new char[n];
2235: if (leftJustify) {
2236: if (neg)
2237: ca[i++] = '-';
2238: else if (leadingSign)
2239: ca[i++] = '+';
2240: else if (leadingSpace)
2241: ca[i++] = ' ';
2242: char[] csx = sx.toCharArray();
2243: jFirst = neg ? 1 : 0;
2244: for (int j = 0; j < nLeadingZeros; i++, j++)
2245: ca[i] = '0';
2246: for (int j = jFirst; j < csx.length; j++, i++)
2247: ca[i] = csx[j];
2248: for (int j = 0; j < nBlanks; i++, j++)
2249: ca[i] = ' ';
2250: } else {
2251: if (!leadingZeros) {
2252: for (i = 0; i < nBlanks; i++)
2253: ca[i] = ' ';
2254: if (neg)
2255: ca[i++] = '-';
2256: else if (leadingSign)
2257: ca[i++] = '+';
2258: else if (leadingSpace)
2259: ca[i++] = ' ';
2260: } else {
2261: if (neg)
2262: ca[i++] = '-';
2263: else if (leadingSign)
2264: ca[i++] = '+';
2265: else if (leadingSpace)
2266: ca[i++] = ' ';
2267: for (int j = 0; j < nBlanks; j++, i++)
2268: ca[i] = '0';
2269: }
2270: for (int j = 0; j < nLeadingZeros; j++, i++)
2271: ca[i] = '0';
2272: char[] csx = sx.toCharArray();
2273: jFirst = neg ? 1 : 0;
2274: for (int j = jFirst; j < csx.length; j++, i++)
2275: ca[i] = csx[j];
2276: }
2277: return new String(ca);
2278: }
2279:
2280: /**
2281: * Format method for the x conversion character and
2282: * short argument.
2283: *
2284: * For x format, the flag character '-', means that
2285: * the output should be left justified within the
2286: * field. The default is to pad with blanks on the
2287: * left. The '#' flag character means to lead with
2288: * '0x'.
2289: *
2290: * The field width is treated as the minimum number
2291: * of characters to be printed. The default is to
2292: * add no padding. Padding is with blanks by
2293: * default.
2294: *
2295: * The precision, if set, is the minimum number of
2296: * digits to appear. Padding is with leading 0s.
2297: * @param x the short to format.
2298: * @return the formatted String.
2299: */
2300: private String printXFormat(short x) {
2301: String sx = null;
2302: if (x == Short.MIN_VALUE)
2303: sx = "8000";
2304: else if (x < 0) {
2305: String t;
2306: if (x == Short.MIN_VALUE)
2307: t = "0";
2308: else {
2309: t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE,
2310: 16);
2311: if (t.charAt(0) == 'F' || t.charAt(0) == 'f')
2312: t = t.substring(16, 32);
2313: }
2314: switch (t.length()) {
2315: case 1:
2316: sx = "800" + t;
2317: break;
2318: case 2:
2319: sx = "80" + t;
2320: break;
2321: case 3:
2322: sx = "8" + t;
2323: break;
2324: case 4:
2325: switch (t.charAt(0)) {
2326: case '1':
2327: sx = "9" + t.substring(1, 4);
2328: break;
2329: case '2':
2330: sx = "a" + t.substring(1, 4);
2331: break;
2332: case '3':
2333: sx = "b" + t.substring(1, 4);
2334: break;
2335: case '4':
2336: sx = "c" + t.substring(1, 4);
2337: break;
2338: case '5':
2339: sx = "d" + t.substring(1, 4);
2340: break;
2341: case '6':
2342: sx = "e" + t.substring(1, 4);
2343: break;
2344: case '7':
2345: sx = "f" + t.substring(1, 4);
2346: break;
2347: }
2348: break;
2349: }
2350: } else
2351: sx = Integer.toString((int) x, 16);
2352: return printXFormat(sx);
2353: }
2354:
2355: /**
2356: * Format method for the x conversion character and
2357: * long argument.
2358: *
2359: * For x format, the flag character '-', means that
2360: * the output should be left justified within the
2361: * field. The default is to pad with blanks on the
2362: * left. The '#' flag character means to lead with
2363: * '0x'.
2364: *
2365: * The field width is treated as the minimum number
2366: * of characters to be printed. The default is to
2367: * add no padding. Padding is with blanks by
2368: * default.
2369: *
2370: * The precision, if set, is the minimum number of
2371: * digits to appear. Padding is with leading 0s.
2372: * @param x the long to format.
2373: * @return the formatted String.
2374: */
2375: private String printXFormat(long x) {
2376: String sx = null;
2377: if (x == Long.MIN_VALUE)
2378: sx = "8000000000000000";
2379: else if (x < 0) {
2380: String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE,
2381: 16);
2382: switch (t.length()) {
2383: case 1:
2384: sx = "800000000000000" + t;
2385: break;
2386: case 2:
2387: sx = "80000000000000" + t;
2388: break;
2389: case 3:
2390: sx = "8000000000000" + t;
2391: break;
2392: case 4:
2393: sx = "800000000000" + t;
2394: break;
2395: case 5:
2396: sx = "80000000000" + t;
2397: break;
2398: case 6:
2399: sx = "8000000000" + t;
2400: break;
2401: case 7:
2402: sx = "800000000" + t;
2403: break;
2404: case 8:
2405: sx = "80000000" + t;
2406: break;
2407: case 9:
2408: sx = "8000000" + t;
2409: break;
2410: case 10:
2411: sx = "800000" + t;
2412: break;
2413: case 11:
2414: sx = "80000" + t;
2415: break;
2416: case 12:
2417: sx = "8000" + t;
2418: break;
2419: case 13:
2420: sx = "800" + t;
2421: break;
2422: case 14:
2423: sx = "80" + t;
2424: break;
2425: case 15:
2426: sx = "8" + t;
2427: break;
2428: case 16:
2429: switch (t.charAt(0)) {
2430: case '1':
2431: sx = "9" + t.substring(1, 16);
2432: break;
2433: case '2':
2434: sx = "a" + t.substring(1, 16);
2435: break;
2436: case '3':
2437: sx = "b" + t.substring(1, 16);
2438: break;
2439: case '4':
2440: sx = "c" + t.substring(1, 16);
2441: break;
2442: case '5':
2443: sx = "d" + t.substring(1, 16);
2444: break;
2445: case '6':
2446: sx = "e" + t.substring(1, 16);
2447: break;
2448: case '7':
2449: sx = "f" + t.substring(1, 16);
2450: break;
2451: }
2452: break;
2453: }
2454: } else
2455: sx = Long.toString(x, 16);
2456: return printXFormat(sx);
2457: }
2458:
2459: /**
2460: * Format method for the x conversion character and
2461: * int argument.
2462: *
2463: * For x format, the flag character '-', means that
2464: * the output should be left justified within the
2465: * field. The default is to pad with blanks on the
2466: * left. The '#' flag character means to lead with
2467: * '0x'.
2468: *
2469: * The field width is treated as the minimum number
2470: * of characters to be printed. The default is to
2471: * add no padding. Padding is with blanks by
2472: * default.
2473: *
2474: * The precision, if set, is the minimum number of
2475: * digits to appear. Padding is with leading 0s.
2476: * @param x the int to format.
2477: * @return the formatted String.
2478: */
2479: private String printXFormat(int x) {
2480: String sx = null;
2481: if (x == Integer.MIN_VALUE)
2482: sx = "80000000";
2483: else if (x < 0) {
2484: String t = Integer.toString((~(-x - 1))
2485: ^ Integer.MIN_VALUE, 16);
2486: switch (t.length()) {
2487: case 1:
2488: sx = "8000000" + t;
2489: break;
2490: case 2:
2491: sx = "800000" + t;
2492: break;
2493: case 3:
2494: sx = "80000" + t;
2495: break;
2496: case 4:
2497: sx = "8000" + t;
2498: break;
2499: case 5:
2500: sx = "800" + t;
2501: break;
2502: case 6:
2503: sx = "80" + t;
2504: break;
2505: case 7:
2506: sx = "8" + t;
2507: break;
2508: case 8:
2509: switch (t.charAt(0)) {
2510: case '1':
2511: sx = "9" + t.substring(1, 8);
2512: break;
2513: case '2':
2514: sx = "a" + t.substring(1, 8);
2515: break;
2516: case '3':
2517: sx = "b" + t.substring(1, 8);
2518: break;
2519: case '4':
2520: sx = "c" + t.substring(1, 8);
2521: break;
2522: case '5':
2523: sx = "d" + t.substring(1, 8);
2524: break;
2525: case '6':
2526: sx = "e" + t.substring(1, 8);
2527: break;
2528: case '7':
2529: sx = "f" + t.substring(1, 8);
2530: break;
2531: }
2532: break;
2533: }
2534: } else
2535: sx = Integer.toString(x, 16);
2536: return printXFormat(sx);
2537: }
2538:
2539: /**
2540: * Utility method for formatting using the x
2541: * conversion character.
2542: * @param sx the String to format, the result of
2543: * converting a short, int, or long to a
2544: * String.
2545: * @return the formatted String.
2546: */
2547: private String printXFormat(String sx) {
2548: int nLeadingZeros = 0;
2549: int nBlanks = 0;
2550: if (sx.equals("0") && precisionSet && precision == 0)
2551: sx = "";
2552: if (precisionSet)
2553: nLeadingZeros = precision - sx.length();
2554: if (nLeadingZeros < 0)
2555: nLeadingZeros = 0;
2556: if (fieldWidthSet) {
2557: nBlanks = fieldWidth - nLeadingZeros - sx.length();
2558: if (alternateForm)
2559: nBlanks = nBlanks - 2;
2560: }
2561: if (nBlanks < 0)
2562: nBlanks = 0;
2563: int n = 0;
2564: if (alternateForm)
2565: n += 2;
2566: n += nLeadingZeros;
2567: n += sx.length();
2568: n += nBlanks;
2569: char[] ca = new char[n];
2570: int i = 0;
2571: if (leftJustify) {
2572: if (alternateForm) {
2573: ca[i++] = '0';
2574: ca[i++] = 'x';
2575: }
2576: for (int j = 0; j < nLeadingZeros; j++, i++)
2577: ca[i] = '0';
2578: char[] csx = sx.toCharArray();
2579: for (int j = 0; j < csx.length; j++, i++)
2580: ca[i] = csx[j];
2581: for (int j = 0; j < nBlanks; j++, i++)
2582: ca[i] = ' ';
2583: } else {
2584: if (!leadingZeros)
2585: for (int j = 0; j < nBlanks; j++, i++)
2586: ca[i] = ' ';
2587: if (alternateForm) {
2588: ca[i++] = '0';
2589: ca[i++] = 'x';
2590: }
2591: if (leadingZeros)
2592: for (int j = 0; j < nBlanks; j++, i++)
2593: ca[i] = '0';
2594: for (int j = 0; j < nLeadingZeros; j++, i++)
2595: ca[i] = '0';
2596: char[] csx = sx.toCharArray();
2597: for (int j = 0; j < csx.length; j++, i++)
2598: ca[i] = csx[j];
2599: }
2600: String caReturn = new String(ca);
2601: if (conversionCharacter == 'X')
2602: caReturn = caReturn.toUpperCase();
2603: return caReturn;
2604: }
2605:
2606: /**
2607: * Format method for the o conversion character and
2608: * short argument.
2609: *
2610: * For o format, the flag character '-', means that
2611: * the output should be left justified within the
2612: * field. The default is to pad with blanks on the
2613: * left. The '#' flag character means that the
2614: * output begins with a leading 0 and the precision
2615: * is increased by 1.
2616: *
2617: * The field width is treated as the minimum number
2618: * of characters to be printed. The default is to
2619: * add no padding. Padding is with blanks by
2620: * default.
2621: *
2622: * The precision, if set, is the minimum number of
2623: * digits to appear. Padding is with leading 0s.
2624: * @param x the short to format.
2625: * @return the formatted String.
2626: */
2627: private String printOFormat(short x) {
2628: String sx = null;
2629: if (x == Short.MIN_VALUE)
2630: sx = "100000";
2631: else if (x < 0) {
2632: String t = Integer.toString((~(-x - 1))
2633: ^ Short.MIN_VALUE, 8);
2634: switch (t.length()) {
2635: case 1:
2636: sx = "10000" + t;
2637: break;
2638: case 2:
2639: sx = "1000" + t;
2640: break;
2641: case 3:
2642: sx = "100" + t;
2643: break;
2644: case 4:
2645: sx = "10" + t;
2646: break;
2647: case 5:
2648: sx = "1" + t;
2649: break;
2650: }
2651: } else
2652: sx = Integer.toString((int) x, 8);
2653: return printOFormat(sx);
2654: }
2655:
2656: /**
2657: * Format method for the o conversion character and
2658: * long argument.
2659: *
2660: * For o format, the flag character '-', means that
2661: * the output should be left justified within the
2662: * field. The default is to pad with blanks on the
2663: * left. The '#' flag character means that the
2664: * output begins with a leading 0 and the precision
2665: * is increased by 1.
2666: *
2667: * The field width is treated as the minimum number
2668: * of characters to be printed. The default is to
2669: * add no padding. Padding is with blanks by
2670: * default.
2671: *
2672: * The precision, if set, is the minimum number of
2673: * digits to appear. Padding is with leading 0s.
2674: * @param x the long to format.
2675: * @return the formatted String.
2676: */
2677: private String printOFormat(long x) {
2678: String sx = null;
2679: if (x == Long.MIN_VALUE)
2680: sx = "1000000000000000000000";
2681: else if (x < 0) {
2682: String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE,
2683: 8);
2684: switch (t.length()) {
2685: case 1:
2686: sx = "100000000000000000000" + t;
2687: break;
2688: case 2:
2689: sx = "10000000000000000000" + t;
2690: break;
2691: case 3:
2692: sx = "1000000000000000000" + t;
2693: break;
2694: case 4:
2695: sx = "100000000000000000" + t;
2696: break;
2697: case 5:
2698: sx = "10000000000000000" + t;
2699: break;
2700: case 6:
2701: sx = "1000000000000000" + t;
2702: break;
2703: case 7:
2704: sx = "100000000000000" + t;
2705: break;
2706: case 8:
2707: sx = "10000000000000" + t;
2708: break;
2709: case 9:
2710: sx = "1000000000000" + t;
2711: break;
2712: case 10:
2713: sx = "100000000000" + t;
2714: break;
2715: case 11:
2716: sx = "10000000000" + t;
2717: break;
2718: case 12:
2719: sx = "1000000000" + t;
2720: break;
2721: case 13:
2722: sx = "100000000" + t;
2723: break;
2724: case 14:
2725: sx = "10000000" + t;
2726: break;
2727: case 15:
2728: sx = "1000000" + t;
2729: break;
2730: case 16:
2731: sx = "100000" + t;
2732: break;
2733: case 17:
2734: sx = "10000" + t;
2735: break;
2736: case 18:
2737: sx = "1000" + t;
2738: break;
2739: case 19:
2740: sx = "100" + t;
2741: break;
2742: case 20:
2743: sx = "10" + t;
2744: break;
2745: case 21:
2746: sx = "1" + t;
2747: break;
2748: }
2749: } else
2750: sx = Long.toString(x, 8);
2751: return printOFormat(sx);
2752: }
2753:
2754: /**
2755: * Format method for the o conversion character and
2756: * int argument.
2757: *
2758: * For o format, the flag character '-', means that
2759: * the output should be left justified within the
2760: * field. The default is to pad with blanks on the
2761: * left. The '#' flag character means that the
2762: * output begins with a leading 0 and the precision
2763: * is increased by 1.
2764: *
2765: * The field width is treated as the minimum number
2766: * of characters to be printed. The default is to
2767: * add no padding. Padding is with blanks by
2768: * default.
2769: *
2770: * The precision, if set, is the minimum number of
2771: * digits to appear. Padding is with leading 0s.
2772: * @param x the int to format.
2773: * @return the formatted String.
2774: */
2775: private String printOFormat(int x) {
2776: String sx = null;
2777: if (x == Integer.MIN_VALUE)
2778: sx = "20000000000";
2779: else if (x < 0) {
2780: String t = Integer.toString((~(-x - 1))
2781: ^ Integer.MIN_VALUE, 8);
2782: switch (t.length()) {
2783: case 1:
2784: sx = "2000000000" + t;
2785: break;
2786: case 2:
2787: sx = "200000000" + t;
2788: break;
2789: case 3:
2790: sx = "20000000" + t;
2791: break;
2792: case 4:
2793: sx = "2000000" + t;
2794: break;
2795: case 5:
2796: sx = "200000" + t;
2797: break;
2798: case 6:
2799: sx = "20000" + t;
2800: break;
2801: case 7:
2802: sx = "2000" + t;
2803: break;
2804: case 8:
2805: sx = "200" + t;
2806: break;
2807: case 9:
2808: sx = "20" + t;
2809: break;
2810: case 10:
2811: sx = "2" + t;
2812: break;
2813: case 11:
2814: sx = "3" + t.substring(1);
2815: break;
2816: }
2817: } else
2818: sx = Integer.toString(x, 8);
2819: return printOFormat(sx);
2820: }
2821:
2822: /**
2823: * Utility method for formatting using the o
2824: * conversion character.
2825: * @param sx the String to format, the result of
2826: * converting a short, int, or long to a
2827: * String.
2828: * @return the formatted String.
2829: */
2830: private String printOFormat(String sx) {
2831: int nLeadingZeros = 0;
2832: int nBlanks = 0;
2833: if (sx.equals("0") && precisionSet && precision == 0)
2834: sx = "";
2835: if (precisionSet)
2836: nLeadingZeros = precision - sx.length();
2837: if (alternateForm)
2838: nLeadingZeros++;
2839: if (nLeadingZeros < 0)
2840: nLeadingZeros = 0;
2841: if (fieldWidthSet)
2842: nBlanks = fieldWidth - nLeadingZeros - sx.length();
2843: if (nBlanks < 0)
2844: nBlanks = 0;
2845: int n = nLeadingZeros + sx.length() + nBlanks;
2846: char[] ca = new char[n];
2847: int i;
2848: if (leftJustify) {
2849: for (i = 0; i < nLeadingZeros; i++)
2850: ca[i] = '0';
2851: char[] csx = sx.toCharArray();
2852: for (int j = 0; j < csx.length; j++, i++)
2853: ca[i] = csx[j];
2854: for (int j = 0; j < nBlanks; j++, i++)
2855: ca[i] = ' ';
2856: } else {
2857: if (leadingZeros)
2858: for (i = 0; i < nBlanks; i++)
2859: ca[i] = '0';
2860: else
2861: for (i = 0; i < nBlanks; i++)
2862: ca[i] = ' ';
2863: for (int j = 0; j < nLeadingZeros; j++, i++)
2864: ca[i] = '0';
2865: char[] csx = sx.toCharArray();
2866: for (int j = 0; j < csx.length; j++, i++)
2867: ca[i] = csx[j];
2868: }
2869: return new String(ca);
2870: }
2871:
2872: /**
2873: * Format method for the c conversion character and
2874: * char argument.
2875: *
2876: * The only flag character that affects c format is
2877: * the '-', meaning that the output should be left
2878: * justified within the field. The default is to
2879: * pad with blanks on the left.
2880: *
2881: * The field width is treated as the minimum number
2882: * of characters to be printed. Padding is with
2883: * blanks by default. The default width is 1.
2884: *
2885: * The precision, if set, is ignored.
2886: * @param x the char to format.
2887: * @return the formatted String.
2888: */
2889: private String printCFormat(char x) {
2890: int nPrint = 1;
2891: int width = fieldWidth;
2892: if (!fieldWidthSet)
2893: width = nPrint;
2894: char[] ca = new char[width];
2895: int i = 0;
2896: if (leftJustify) {
2897: ca[0] = x;
2898: for (i = 1; i <= width - nPrint; i++)
2899: ca[i] = ' ';
2900: } else {
2901: for (i = 0; i < width - nPrint; i++)
2902: ca[i] = ' ';
2903: ca[i] = x;
2904: }
2905: return new String(ca);
2906: }
2907:
2908: /**
2909: * Format method for the s conversion character and
2910: * String argument.
2911: *
2912: * The only flag character that affects s format is
2913: * the '-', meaning that the output should be left
2914: * justified within the field. The default is to
2915: * pad with blanks on the left.
2916: *
2917: * The field width is treated as the minimum number
2918: * of characters to be printed. The default is the
2919: * smaller of the number of characters in the the
2920: * input and the precision. Padding is with blanks
2921: * by default.
2922: *
2923: * The precision, if set, specifies the maximum
2924: * number of characters to be printed from the
2925: * string. A null digit string is treated
2926: * as a 0. The default is not to set a maximum
2927: * number of characters to be printed.
2928: * @param x the String to format.
2929: * @return the formatted String.
2930: */
2931: private String printSFormat(String x) {
2932: int nPrint = x.length();
2933: int width = fieldWidth;
2934: if (precisionSet && nPrint > precision)
2935: nPrint = precision;
2936: if (!fieldWidthSet)
2937: width = nPrint;
2938: int n = 0;
2939: if (width > nPrint)
2940: n += width - nPrint;
2941: if (nPrint >= x.length())
2942: n += x.length();
2943: else
2944: n += nPrint;
2945: char[] ca = new char[n];
2946: int i = 0;
2947: if (leftJustify) {
2948: if (nPrint >= x.length()) {
2949: char[] csx = x.toCharArray();
2950: for (i = 0; i < x.length(); i++)
2951: ca[i] = csx[i];
2952: } else {
2953: char[] csx = x.substring(0, nPrint).toCharArray();
2954: for (i = 0; i < nPrint; i++)
2955: ca[i] = csx[i];
2956: }
2957: for (int j = 0; j < width - nPrint; j++, i++)
2958: ca[i] = ' ';
2959: } else {
2960: for (i = 0; i < width - nPrint; i++)
2961: ca[i] = ' ';
2962: if (nPrint >= x.length()) {
2963: char[] csx = x.toCharArray();
2964: for (int j = 0; j < x.length(); i++, j++)
2965: ca[i] = csx[j];
2966: } else {
2967: char[] csx = x.substring(0, nPrint).toCharArray();
2968: for (int j = 0; j < nPrint; i++, j++)
2969: ca[i] = csx[j];
2970: }
2971: }
2972: return new String(ca);
2973: }
2974:
2975: /**
2976: * Check for a conversion character. If it is
2977: * there, store it.
2978: * @param x the String to format.
2979: * @return <code>true</code> if the conversion
2980: * character is there, and
2981: * <code>false</code> otherwise.
2982: */
2983: private boolean setConversionCharacter() {
2984: /* idfgGoxXeEcs */
2985: boolean ret = false;
2986: conversionCharacter = '\0';
2987: if (pos < fmt.length()) {
2988: char c = fmt.charAt(pos);
2989: if (c == 'i' || c == 'd' || c == 'f' || c == 'g'
2990: || c == 'G' || c == 'o' || c == 'x' || c == 'X'
2991: || c == 'e' || c == 'E' || c == 'c' || c == 's'
2992: || c == '%') {
2993: conversionCharacter = c;
2994: pos++;
2995: ret = true;
2996: }
2997: }
2998: return ret;
2999: }
3000:
3001: /**
3002: * Check for an h, l, or L in a format. An L is
3003: * used to control the minimum number of digits
3004: * in an exponent when using floating point
3005: * formats. An l or h is used to control
3006: * conversion of the input to a long or short,
3007: * respectively, before formatting. If any of
3008: * these is present, store them.
3009: */
3010: private void setOptionalHL() {
3011: optionalh = false;
3012: optionall = false;
3013: optionalL = false;
3014: if (pos < fmt.length()) {
3015: char c = fmt.charAt(pos);
3016: if (c == 'h') {
3017: optionalh = true;
3018: pos++;
3019: } else if (c == 'l') {
3020: optionall = true;
3021: pos++;
3022: } else if (c == 'L') {
3023: optionalL = true;
3024: pos++;
3025: }
3026: }
3027: }
3028:
3029: /**
3030: * Set the precision.
3031: */
3032: private void setPrecision() {
3033: int firstPos = pos;
3034: precisionSet = false;
3035: if (pos < fmt.length() && fmt.charAt(pos) == '.') {
3036: pos++;
3037: if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) {
3038: pos++;
3039: if (!setPrecisionArgPosition()) {
3040: variablePrecision = true;
3041: precisionSet = true;
3042: }
3043: return;
3044: } else {
3045: while (pos < fmt.length()) {
3046: char c = fmt.charAt(pos);
3047: if (Character.isDigit(c))
3048: pos++;
3049: else
3050: break;
3051: }
3052: if (pos > firstPos + 1) {
3053: String sz = fmt.substring(firstPos + 1, pos);
3054: precision = Integer.parseInt(sz);
3055: precisionSet = true;
3056: }
3057: }
3058: }
3059: }
3060:
3061: /**
3062: * Set the field width.
3063: */
3064: private void setFieldWidth() {
3065: int firstPos = pos;
3066: fieldWidth = 0;
3067: fieldWidthSet = false;
3068: if ((pos < fmt.length()) && (fmt.charAt(pos) == '*')) {
3069: pos++;
3070: if (!setFieldWidthArgPosition()) {
3071: variableFieldWidth = true;
3072: fieldWidthSet = true;
3073: }
3074: } else {
3075: while (pos < fmt.length()) {
3076: char c = fmt.charAt(pos);
3077: if (Character.isDigit(c))
3078: pos++;
3079: else
3080: break;
3081: }
3082: if (firstPos < pos && firstPos < fmt.length()) {
3083: String sz = fmt.substring(firstPos, pos);
3084: fieldWidth = Integer.parseInt(sz);
3085: fieldWidthSet = true;
3086: }
3087: }
3088: }
3089:
3090: /**
3091: * Store the digits <code>n</code> in %n$ forms.
3092: */
3093: private void setArgPosition() {
3094: int xPos;
3095: for (xPos = pos; xPos < fmt.length(); xPos++) {
3096: if (!Character.isDigit(fmt.charAt(xPos)))
3097: break;
3098: }
3099: if (xPos > pos && xPos < fmt.length()) {
3100: if (fmt.charAt(xPos) == '$') {
3101: positionalSpecification = true;
3102: argumentPosition = Integer.parseInt(fmt.substring(
3103: pos, xPos));
3104: pos = xPos + 1;
3105: }
3106: }
3107: }
3108:
3109: /**
3110: * Store the digits <code>n</code> in *n$ forms.
3111: */
3112: private boolean setFieldWidthArgPosition() {
3113: boolean ret = false;
3114: int xPos;
3115: for (xPos = pos; xPos < fmt.length(); xPos++) {
3116: if (!Character.isDigit(fmt.charAt(xPos)))
3117: break;
3118: }
3119: if (xPos > pos && xPos < fmt.length()) {
3120: if (fmt.charAt(xPos) == '$') {
3121: positionalFieldWidth = true;
3122: argumentPositionForFieldWidth = Integer
3123: .parseInt(fmt.substring(pos, xPos));
3124: pos = xPos + 1;
3125: ret = true;
3126: }
3127: }
3128: return ret;
3129: }
3130:
3131: /**
3132: * Store the digits <code>n</code> in *n$ forms.
3133: */
3134: private boolean setPrecisionArgPosition() {
3135: boolean ret = false;
3136: int xPos;
3137: for (xPos = pos; xPos < fmt.length(); xPos++) {
3138: if (!Character.isDigit(fmt.charAt(xPos)))
3139: break;
3140: }
3141: if (xPos > pos && xPos < fmt.length()) {
3142: if (fmt.charAt(xPos) == '$') {
3143: positionalPrecision = true;
3144: argumentPositionForPrecision = Integer.parseInt(fmt
3145: .substring(pos, xPos));
3146: pos = xPos + 1;
3147: ret = true;
3148: }
3149: }
3150: return ret;
3151: }
3152:
3153: boolean isPositionalSpecification() {
3154: return positionalSpecification;
3155: }
3156:
3157: int getArgumentPosition() {
3158: return argumentPosition;
3159: }
3160:
3161: boolean isPositionalFieldWidth() {
3162: return positionalFieldWidth;
3163: }
3164:
3165: int getArgumentPositionForFieldWidth() {
3166: return argumentPositionForFieldWidth;
3167: }
3168:
3169: boolean isPositionalPrecision() {
3170: return positionalPrecision;
3171: }
3172:
3173: int getArgumentPositionForPrecision() {
3174: return argumentPositionForPrecision;
3175: }
3176:
3177: /**
3178: * Set flag characters, one of '-+#0 or a space.
3179: */
3180: private void setFlagCharacters() {
3181: /* '-+ #0 */
3182: thousands = false;
3183: leftJustify = false;
3184: leadingSign = false;
3185: leadingSpace = false;
3186: alternateForm = false;
3187: leadingZeros = false;
3188: for (; pos < fmt.length(); pos++) {
3189: char c = fmt.charAt(pos);
3190: if (c == '\'')
3191: thousands = true;
3192: else if (c == '-') {
3193: leftJustify = true;
3194: leadingZeros = false;
3195: } else if (c == '+') {
3196: leadingSign = true;
3197: leadingSpace = false;
3198: } else if (c == ' ') {
3199: if (!leadingSign)
3200: leadingSpace = true;
3201: } else if (c == '#')
3202: alternateForm = true;
3203: else if (c == '0') {
3204: if (!leftJustify)
3205: leadingZeros = true;
3206: } else
3207: break;
3208: }
3209: }
3210:
3211: /**
3212: * The integer portion of the result of a decimal
3213: * conversion (i, d, u, f, g, or G) will be
3214: * formatted with thousands' grouping characters.
3215: * For other conversions the flag is ignored.
3216: */
3217: private boolean thousands = false;
3218: /**
3219: * The result of the conversion will be
3220: * left-justified within the field.
3221: */
3222: private boolean leftJustify = false;
3223: /**
3224: * The result of a signed conversion will always
3225: * begin with a sign (+ or -).
3226: */
3227: private boolean leadingSign = false;
3228: /**
3229: * Flag indicating that left padding with spaces is
3230: * specified.
3231: */
3232: private boolean leadingSpace = false;
3233: /**
3234: * For an o conversion, increase the precision to
3235: * force the first digit of the result to be a
3236: * zero. For x (or X) conversions, a non-zero
3237: * result will have 0x (or 0X) prepended to it.
3238: * For e, E, f, g, or G conversions, the result
3239: * will always contain a radix character, even if
3240: * no digits follow the point. For g and G
3241: * conversions, trailing zeros will not be removed
3242: * from the result.
3243: */
3244: private boolean alternateForm = false;
3245: /**
3246: * Flag indicating that left padding with zeroes is
3247: * specified.
3248: */
3249: private boolean leadingZeros = false;
3250: /**
3251: * Flag indicating that the field width is *.
3252: */
3253: private boolean variableFieldWidth = false;
3254: /**
3255: * If the converted value has fewer bytes than the
3256: * field width, it will be padded with spaces or
3257: * zeroes.
3258: */
3259: private int fieldWidth = 0;
3260: /**
3261: * Flag indicating whether or not the field width
3262: * has been set.
3263: */
3264: private boolean fieldWidthSet = false;
3265: /**
3266: * The minimum number of digits to appear for the
3267: * d, i, o, u, x, or X conversions. The number of
3268: * digits to appear after the radix character for
3269: * the e, E, and f conversions. The maximum number
3270: * of significant digits for the g and G
3271: * conversions. The maximum number of bytes to be
3272: * printed from a string in s and S conversions.
3273: */
3274: private int precision = 0;
3275: /** Default precision. */
3276: private final static int defaultDigits = 6;
3277: /**
3278: * Flag indicating that the precision is *.
3279: */
3280: private boolean variablePrecision = false;
3281: /**
3282: * Flag indicating whether or not the precision has
3283: * been set.
3284: */
3285: private boolean precisionSet = false;
3286: /*
3287: */
3288: private boolean positionalSpecification = false;
3289: private int argumentPosition = 0;
3290: private boolean positionalFieldWidth = false;
3291: private int argumentPositionForFieldWidth = 0;
3292: private boolean positionalPrecision = false;
3293: private int argumentPositionForPrecision = 0;
3294: /**
3295: * Flag specifying that a following d, i, o, u, x,
3296: * or X conversion character applies to a type
3297: * short int.
3298: */
3299: private boolean optionalh = false;
3300: /**
3301: * Flag specifying that a following d, i, o, u, x,
3302: * or X conversion character applies to a type lont
3303: * int argument.
3304: */
3305: private boolean optionall = false;
3306: /**
3307: * Flag specifying that a following e, E, f, g, or
3308: * G conversion character applies to a type double
3309: * argument. This is a noop in Java.
3310: */
3311: private boolean optionalL = false;
3312: /** Control string type. */
3313: private char conversionCharacter = '\0';
3314: /**
3315: * Position within the control string. Used by
3316: * the constructor.
3317: */
3318: private int pos = 0;
3319: /** Literal or control format string. */
3320: private String fmt;
3321: }
3322:
3323: /** Vector of control strings and format literals. */
3324: private Vector vFmt = new Vector();
3325: /** Character position. Used by the constructor. */
3326: private int cPos = 0;
3327: /** Character position. Used by the constructor. */
3328: private DecimalFormatSymbols dfs = null;
3329: }
|