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