001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028//
029// (c) 2000 Sun Microsystems, Inc.
030// ALL RIGHTS RESERVED
031//
032// License Grant-
033//
034//
035// Permission to use, copy, modify, and distribute this Software and its
036// documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is
037// hereby granted.
038//
039// This Software is provided "AS IS".  All express warranties, including any
040// implied warranty of merchantability, satisfactory quality, fitness for a
041// particular purpose, or non-infringement, are disclaimed, except to the extent
042// that such disclaimers are held to be legally invalid.
043//
044// You acknowledge that Software is not designed, licensed or intended for use in
045// the design, construction, operation or maintenance of any nuclear facility
046// ("High Risk Activities").  Sun disclaims any express or implied warranty of
047// fitness for such uses.
048//
049// Please refer to the file http://www.sun.com/policies/trademarks/ for further
050// important trademark information and to
051// http://java.sun.com/nav/business/index.html for further important licensing
052// information for the Java Technology.
053//
054
055package org.opencms.util;
056
057import org.opencms.main.CmsIllegalArgumentException;
058
059import java.text.DecimalFormatSymbols;
060import java.util.Enumeration;
061import java.util.Locale;
062import java.util.Vector;
063
064/**
065 * PrintfFormat allows the formatting of an array of
066 * objects embedded within a string.  Primitive types
067 * must be passed using wrapper types.  The formatting
068 * is controlled by a control string.
069 *<p>
070 * A control string is a Java string that contains a
071 * control specification.  The control specification
072 * starts at the first percent sign (%) in the string,
073 * provided that this percent sign
074 *<ol>
075 *<li>is not escaped protected by a matching % or is
076 * not an escape % character,
077 *<li>is not at the end of the format string, and
078 *<li>precedes a sequence of characters that parses as
079 * a valid control specification.
080 *</ol>
081 *</p><p>
082 * A control specification usually takes the form:
083 *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
084 *                { [hlL] }+ [idfgGoxXeEcs]
085 *</pre>
086 * There are variants of this basic form that are
087 * discussed below.</p>
088 *<p>
089 * The format is composed of zero or more directives
090 * defined as follows:
091 *<ul>
092 *<li>ordinary characters, which are simply copied to
093 * the output stream;
094 *<li>escape sequences, which represent non-graphic
095 * characters; and
096 *<li>conversion specifications,  each of which
097 * results in the fetching of zero or more arguments.
098 *</ul></p>
099 *<p>
100 * The results are undefined if there are insufficient
101 * arguments for the format.  Usually an unchecked
102 * exception will be thrown.  If the format is
103 * exhausted while arguments remain, the excess
104 * arguments are evaluated but are otherwise ignored.
105 * In format strings containing the % form of
106 * conversion specifications, each argument in the
107 * argument list is used exactly once.</p>
108 * <p>
109 * Conversions can be applied to the <code>n</code>th
110 * argument after the format in the argument list,
111 * rather than to the next unused argument.  In this
112 * case, the conversion characer % is replaced by the
113 * sequence %<code>n</code>$, where <code>n</code> is
114 * a decimal integer giving the position of the
115 * argument in the argument list.</p>
116 * <p>
117 * In format strings containing the %<code>n</code>$
118 * form of conversion specifications, each argument
119 * in the argument list is used exactly once.</p>
120 *
121 *<h4>Escape Sequences</h4>
122 *<p>
123 * The following table lists escape sequences and
124 * associated actions on display devices capable of
125 * the action.
126 *<table>
127 *<tr><th align=left>Sequence</th>
128 *    <th align=left>Name</th>
129 *    <th align=left>Description</th></tr>
130 *<tr><td>\\</td><td>backlash</td><td>None.
131 *</td></tr>
132 *<tr><td>\a</td><td>alert</td><td>Attempts to alert
133 *          the user through audible or visible
134 *          notification.
135 *</td></tr>
136 *<tr><td>\b</td><td>backspace</td><td>Moves the
137 *          printing position to one column before
138 *          the current position, unless the
139 *          current position is the start of a line.
140 *</td></tr>
141 *<tr><td>\f</td><td>form-feed</td><td>Moves the
142 *          printing position to the initial
143 *          printing position of the next logical
144 *          page.
145 *</td></tr>
146 *<tr><td>\n</td><td>newline</td><td>Moves the
147 *          printing position to the start of the
148 *          next line.
149 *</td></tr>
150 *<tr><td>\r</td><td>carriage-return</td><td>Moves
151 *          the printing position to the start of
152 *          the current line.
153 *</td></tr>
154 *<tr><td>\t</td><td>tab</td><td>Moves the printing
155 *          position to the next implementation-
156 *          defined horizontal tab position.
157 *</td></tr>
158 *<tr><td>\v</td><td>vertical-tab</td><td>Moves the
159 *          printing position to the start of the
160 *          next implementation-defined vertical
161 *          tab position.
162 *</td></tr>
163 *</table></p>
164 *<h4>Conversion Specifications</h4>
165 *<p>
166 * Each conversion specification is introduced by
167 * the percent sign character (%).  After the character
168 * %, the following appear in sequence:</p>
169 *<p>
170 * Zero or more flags (in any order), which modify the
171 * meaning of the conversion specification.</p>
172 *<p>
173 * An optional minimum field width.  If the converted
174 * value has fewer characters than the field width, it
175 * will be padded with spaces by default on the left;
176 * t will be padded on the right, if the left-
177 * adjustment flag (-), described below, is given to
178 * the field width.  The field width takes the form
179 * of a decimal integer.  If the conversion character
180 * is s, the field width is the the minimum number of
181 * characters to be printed.</p>
182 *<p>
183 * An optional precision that gives the minumum number
184 * of digits to appear for the d, i, o, x or X
185 * conversions (the field is padded with leading
186 * zeros); the number of digits to appear after the
187 * radix character for the e, E, and f conversions,
188 * the maximum number of significant digits for the g
189 * and G conversions; or the maximum number of
190 * characters to be written from a string is s and S
191 * conversions.  The precision takes the form of an
192 * optional decimal digit string, where a null digit
193 * string is treated as 0.  If a precision appears
194 * with a c conversion character the precision is
195 * ignored.
196 * </p>
197 *<p>
198 * An optional h specifies that a following d, i, o,
199 * x, or X conversion character applies to a type
200 * short argument (the argument will be promoted
201 * according to the integral promotions and its value
202 * converted to type short before printing).</p>
203 *<p>
204 * An optional l (ell) specifies that a following
205 * d, i, o, x, or X conversion character applies to a
206 * type long argument.</p>
207 *<p>
208 * A field width or precision may be indicated by an
209 * asterisk (*) instead of a digit string.  In this
210 * case, an integer argument supplised the field width
211 * precision.  The argument that is actually converted
212 * is not fetched until the conversion letter is seen,
213 * so the the arguments specifying field width or
214 * precision must appear before the argument (if any)
215 * to be converted.  If the precision argument is
216 * negative, it will be changed to zero.  A negative
217 * field width argument is taken as a - flag, followed
218 * by a positive field width.</p>
219 * <p>
220 * In format strings containing the %<code>n</code>$
221 * form of a conversion specification, a field width
222 * or precision may be indicated by the sequence
223 * *<code>m</code>$, where m is a decimal integer
224 * giving the position in the argument list (after the
225 * format argument) of an integer argument containing
226 * the field width or precision.</p>
227 * <p>
228 * The format can contain either numbered argument
229 * specifications (that is, %<code>n</code>$ and
230 * *<code>m</code>$), or unnumbered argument
231 * specifications (that is % and *), but normally not
232 * both.  The only exception to this is that %% can
233 * be mixed with the %<code>n</code>$ form.  The
234 * results of mixing numbered and unnumbered argument
235 * specifications in a format string are undefined.</p>
236 *
237 *<h4>Flag Characters</h4>
238 *<p>
239 * The flags and their meanings are:</p>
240 *<dl>
241 * <dt>'<dd> integer portion of the result of a
242 *      decimal conversion (%i, %d, %f, %g, or %G) will
243 *      be formatted with thousands' grouping
244 *      characters.  For other conversions the flag
245 *      is ignored.  The non-monetary grouping
246 *      character is used.
247 * <dt>-<dd> result of the conversion is left-justified
248 *      within the field.  (It will be right-justified
249 *      if this flag is not specified).
250 * <dt>+<dd> result of a signed conversion always
251 *      begins with a sign (+ or -).  (It will begin
252 *      with a sign only when a negative value is
253 *      converted if this flag is not specified.)
254 * <dt>&lt;space&gt;<dd> If the first character of a
255 *      signed conversion is not a sign, a space
256 *      character will be placed before the result.
257 *      This means that if the space character and +
258 *      flags both appear, the space flag will be
259 *      ignored.
260 * <dt>#<dd> value is to be converted to an alternative
261 *      form.  For c, d, i, and s conversions, the flag
262 *      has no effect.  For o conversion, it increases
263 *      the precision to force the first digit of the
264 *      result to be a zero.  For x or X conversion, a
265 *      non-zero result has 0x or 0X prefixed to it,
266 *      respectively.  For e, E, f, g, and G
267 *      conversions, the result always contains a radix
268 *      character, even if no digits follow the radix
269 *      character (normally, a decimal point appears in
270 *      the result of these conversions only if a digit
271 *      follows it).  For g and G conversions, trailing
272 *      zeros will not be removed from the result as
273 *      they normally are.
274 * <dt>0<dd> d, i, o, x, X, e, E, f, g, and G
275 *      conversions, leading zeros (following any
276 *      indication of sign or base) are used to pad to
277 *      the field width;  no space padding is
278 *      performed.  If the 0 and - flags both appear,
279 *      the 0 flag is ignored.  For d, i, o, x, and X
280 *      conversions, if a precision is specified, the
281 *      0 flag will be ignored. For c conversions,
282 *      the flag is ignored.
283 *</dl>
284 *
285 *<h4>Conversion Characters</h4>
286 *<p>
287 * Each conversion character results in fetching zero
288 * or more arguments.  The results are undefined if
289 * there are insufficient arguments for the format.
290 * Usually, an unchecked exception will be thrown.
291 * If the format is exhausted while arguments remain,
292 * the excess arguments are ignored.</p>
293 *
294 *<p>
295 * The conversion characters and their meanings are:
296 *</p>
297 *<dl>
298 * <dt>d,i<dd>The int argument is converted to a
299 *        signed decimal in the style [-]dddd.  The
300 *        precision specifies the minimum number of
301 *        digits to appear;  if the value being
302 *        converted can be represented in fewer
303 *        digits, it will be expanded with leading
304 *        zeros.  The default precision is 1.  The
305 *        result of converting 0 with an explicit
306 *        precision of 0 is no characters.
307 * <dt>o<dd> The int argument is converted to unsigned
308 *        octal format in the style ddddd.  The
309 *        precision specifies the minimum number of
310 *        digits to appear;  if the value being
311 *        converted can be represented in fewer
312 *        digits, it will be expanded with leading
313 *        zeros.  The default precision is 1.  The
314 *        result of converting 0 with an explicit
315 *        precision of 0 is no characters.
316 * <dt>x<dd> The int argument is converted to unsigned
317 *        hexadecimal format in the style dddd;  the
318 *        letters abcdef are used.  The precision
319 *        specifies the minimum numberof digits to
320 *        appear; if the value being converted can be
321 *        represented in fewer digits, it will be
322 *        expanded with leading zeros.  The default
323 *        precision is 1.  The result of converting 0
324 *        with an explicit precision of 0 is no
325 *        characters.
326 * <dt>X<dd> Behaves the same as the x conversion
327 *        character except that letters ABCDEF are
328 *        used instead of abcdef.
329 * <dt>f<dd> The floating point number argument is
330 *        written in decimal notation in the style
331 *        [-]ddd.ddd, where the number of digits after
332 *        the radix character (shown here as a decimal
333 *        point) is equal to the precision
334 *        specification.  A Locale is used to determine
335 *        the radix character to use in this format.
336 *        If the precision is omitted from the
337 *        argument, six digits are written after the
338 *        radix character;  if the precision is
339 *        explicitly 0 and the # flag is not specified,
340 *        no radix character appears.  If a radix
341 *        character appears, at least 1 digit appears
342 *        before it.  The value is rounded to the
343 *        appropriate number of digits.
344 * <dt>e,E<dd>The floating point number argument is
345 *        written in the style [-]d.ddde{+-}dd
346 *        (the symbols {+-} indicate either a plus or
347 *        minus sign), where there is one digit before
348 *        the radix character (shown here as a decimal
349 *        point) and the number of digits after it is
350 *        equal to the precision.  A Locale is used to
351 *        determine the radix character to use in this
352 *        format.  When the precision is missing, six
353 *        digits are written after the radix character;
354 *        if the precision is 0 and the # flag is not
355 *        specified, no radix character appears.  The
356 *        E conversion will produce a number with E
357 *        instead of e introducing the exponent.  The
358 *        exponent always contains at least two digits.
359 *        However, if the value to be written requires
360 *        an exponent greater than two digits,
361 *        additional exponent digits are written as
362 *        necessary.  The value is rounded to the
363 *        appropriate number of digits.
364 * <dt>g,G<dd>The floating point number argument is
365 *        written in style f or e (or in sytle E in the
366 *        case of a G conversion character), with the
367 *        precision specifying the number of
368 *        significant digits.  If the precision is
369 *        zero, it is taken as one.  The style used
370 *        depends on the value converted:  style e
371 *        (or E) will be used only if the exponent
372 *        resulting from the conversion is less than
373 *        -4 or greater than or equal to the precision.
374 *        Trailing zeros are removed from the result.
375 *        A radix character appears only if it is
376 *        followed by a digit.
377 * <dt>c,C<dd>The integer argument is converted to a
378 *        char and the result is written.
379 *
380 * <dt>s,S<dd>The argument is taken to be a string and
381 *        bytes from the string are written until the
382 *        end of the string or the number of bytes
383 *        indicated by the precision specification of
384 *        the argument is reached.  If the precision
385 *        is omitted from the argument, it is taken to
386 *        be infinite, so all characters up to the end
387 *        of the string are written.
388 * <dt>%<dd>Write a % character;  no argument is
389 *        converted.
390 *</dl>
391 *<p>
392 * If a conversion specification does not match one of
393 * the above forms, an IllegalArgumentException is
394 * thrown and the instance of PrintfFormat is not
395 * created.</p>
396 *<p>
397 * If a floating point value is the internal
398 * representation for infinity, the output is
399 * [+]Infinity, where Infinity is either Infinity or
400 * Inf, depending on the desired output string length.
401 * Printing of the sign follows the rules described
402 * above.</p>
403 *<p>
404 * If a floating point value is the internal
405 * representation for "not-a-number," the output is
406 * [+]NaN.  Printing of the sign follows the rules
407 * described above.</p>
408 *<p>
409 * In no case does a non-existent or small field width
410 * cause truncation of a field;  if the result of a
411 * conversion is wider than the field width, the field
412 * is simply expanded to contain the conversion result.
413 *</p>
414 *<p>
415 * The behavior is like printf.  One exception is that
416 * the minimum number of exponent digits is 3 instead
417 * of 2 for e and E formats when the optional L is used
418 * before the e, E, g, or G conversion character.  The
419 * optional L does not imply conversion to a long long
420 * double. </p>
421 * <p>
422 * The biggest divergence from the C printf
423 * specification is in the use of 16 bit characters.
424 * This allows the handling of characters beyond the
425 * small ASCII character set and allows the utility to
426 * interoperate correctly with the rest of the Java
427 * runtime environment.</p>
428 *<p>
429 * Omissions from the C printf specification are
430 * numerous.  All the known omissions are present
431 * because Java never uses bytes to represent
432 * characters and does not have pointers:</p>
433 *<ul>
434 * <li>%c is the same as %C.
435 * <li>%s is the same as %S.
436 * <li>u, p, and n conversion characters.
437 * <li>%ws format.
438 * <li>h modifier applied to an n conversion character.
439 * <li>l (ell) modifier applied to the c, n, or s
440 * conversion characters.
441 * <li>ll (ell ell) modifier to d, i, o, u, x, or X
442 * conversion characters.
443 * <li>ll (ell ell) modifier to an n conversion
444 * character.
445 * <li>c, C, d,i,o,u,x, and X conversion characters
446 * apply to Byte, Character, Short, Integer, Long
447 * types.
448 * <li>f, e, E, g, and G conversion characters apply
449 * to Float and Double types.
450 * <li>s and S conversion characters apply to String
451 * types.
452 * <li>All other reference types can be formatted
453 * using the s or S conversion characters only.
454 *</ul>
455 * <p>
456 * Most of this specification is quoted from the Unix
457 * man page for the sprintf utility.</p>
458 *
459 * @since 6.0.0
460 */
461public class PrintfFormat {
462
463    /**
464     *<p>
465     * ConversionSpecification allows the formatting of
466     * a single primitive or object embedded within a
467     * string.  The formatting is controlled by a
468     * format string.  Only one Java primitive or
469     * object can be formatted at a time.
470     *<p>
471     * A format string is a Java string that contains
472     * a control string.  The control string starts at
473     * the first percent sign (%) in the string,
474     * provided that this percent sign
475     *<ol>
476     *<li>is not escaped protected by a matching % or
477     *     is not an escape % character,
478     *<li>is not at the end of the format string, and
479     *<li>precedes a sequence of characters that parses
480     *     as a valid control string.
481     *</ol>
482     *<p>
483     * A control string takes the form:
484     *<pre> % ['-+ #0]* [0..9]* { . [0..9]* }+
485     *                { [hlL] }+ [idfgGoxXeEcs]
486     *</pre>
487     *<p>
488     * The behavior is like printf.  One (hopefully the
489     * only) exception is that the minimum number of
490     * exponent digits is 3 instead of 2 for e and E
491     * formats when the optional L is used before the
492     * e, E, g, or G conversion character.  The
493     * optional L does not imply conversion to a long
494     * long double.
495     */
496    private final class ConversionSpecification {
497
498        /** Default precision. */
499        private static final int DEFAULT_DIGITS = 6;
500
501        /**
502         * For an o conversion, increase the precision to
503         * force the first digit of the result to be a
504         * zero.  For x (or X) conversions, a non-zero
505         * result will have 0x (or 0X) prepended to it.
506         * For e, E, f, g, or G conversions, the result
507         * will always contain a radix character, even if
508         * no digits follow the point.  For g and G
509         * conversions, trailing zeros will not be removed
510         * from the result.
511         */
512        private boolean m_alternateForm;
513
514        /** Internal variable. */
515        private int m_argumentPosition;
516
517        /** Internal variable. */
518        private int m_argumentPositionForFieldWidth;
519
520        /** Internal variable. */
521        private int m_argumentPositionForPrecision;
522
523        /** Control string type. */
524        private char m_conversionCharacter;
525
526        /**
527         * If the converted value has fewer bytes than the
528         * field width, it will be padded with spaces or
529         * zeroes.
530         */
531        private int m_fieldWidth;
532
533        /**
534         * Flag indicating whether or not the field width
535         * has been set.
536         */
537        private boolean m_fieldWidthSet;
538
539        /** Literal or control format string. */
540        private String m_fmt;
541
542        /**
543         * The result of a signed conversion will always
544         * begin with a sign (+ or -).
545         */
546        private boolean m_leadingSign;
547
548        /**
549         * Flag indicating that left padding with spaces is
550         * specified.
551         */
552        private boolean m_leadingSpace;
553
554        /**
555         * Flag indicating that left padding with zeroes is
556         * specified.
557         */
558        private boolean m_leadingZeros;
559
560        /**
561         * The result of the conversion will be
562         * left-justified within the field.
563         */
564        private boolean m_leftJustify;
565
566        /**
567         * Flag specifying that a following d, i, o, u, x,
568         * or X conversion character applies to a type
569         * short int.
570         */
571        private boolean m_optionalh;
572
573        /**
574         * Flag specifying that a following d, i, o, u, x,
575         * or X conversion character applies to a type lont
576         * int argument.
577         */
578        private boolean m_optionall;
579
580        /**
581         * Flag specifying that a following e, E, f, g, or
582         * G conversion character applies to a type double
583         * argument.  This is a noop in Java.
584         */
585        private boolean m_optionalL;
586
587        /**
588         * Position within the control string.  Used by
589         * the constructor.
590         */
591        private int m_pos;
592
593        /** Internal variable. */
594        private boolean m_positionalFieldWidth;
595
596        /** Internal variable. */
597        private boolean m_positionalPrecision;
598
599        /** Internal variable. */
600        private boolean m_positionalSpecification;
601
602        /**
603         * The minimum number of digits to appear for the
604         * d, i, o, u, x, or X conversions.  The number of
605         * digits to appear after the radix character for
606         * the e, E, and f conversions.  The maximum number
607         *  of significant digits for the g and G
608         * conversions.  The maximum number of bytes to be
609         * printed from a string in s and S conversions.
610         */
611        private int m_precision;
612
613        /**
614         * Flag indicating whether or not the precision has
615         * been set.
616         */
617        private boolean m_precisionSet;
618
619        /**
620         * The integer portion of the result of a decimal
621         * conversion (i, d, u, f, g, or G) will be
622         * formatted with thousands' grouping characters.
623         * For other conversions the flag is ignored.
624         */
625        private boolean m_thousands;
626
627        /**
628         * Flag indicating that the field width is *.
629         */
630        private boolean m_variableFieldWidth;
631
632        /**
633         * Flag indicating that the precision is *.
634         */
635        private boolean m_variablePrecision;
636
637        /**
638         * Constructor.  Used to prepare an instance
639         * to hold a literal, not a control string.
640         */
641        ConversionSpecification() {
642
643            // empty
644        }
645
646        /**
647         * Constructor for a conversion specification.
648         * The argument must begin with a % and end
649         * with the conversion character for the
650         * conversion specification.
651         * @param fmtArg  String specifying the
652         *     conversion specification.
653         * @exception CmsIllegalArgumentException if the
654         *     input string is null, zero length, or
655         *     otherwise malformed.
656         */
657        ConversionSpecification(String fmtArg)
658        throws CmsIllegalArgumentException {
659
660            if (fmtArg == null) {
661                throw new NullPointerException();
662            }
663            if (fmtArg.length() == 0) {
664                throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_CONTROL_STRING_LENGTH_0));
665            }
666            if (fmtArg.charAt(0) == '%') {
667                m_fmt = fmtArg;
668                m_pos = 1;
669                setArgPosition();
670                setFlagCharacters();
671                setFieldWidth();
672                setPrecision();
673                setOptionalHL();
674                if (setConversionCharacter()) {
675                    if (m_pos == fmtArg.length()) {
676                        if (m_leadingZeros && m_leftJustify) {
677                            m_leadingZeros = false;
678                        }
679                        if (m_precisionSet && m_leadingZeros) {
680                            if ((m_conversionCharacter == 'd')
681                                || (m_conversionCharacter == 'i')
682                                || (m_conversionCharacter == 'o')
683                                || (m_conversionCharacter == 'x')) {
684                                m_leadingZeros = false;
685                            }
686                        }
687                    } else {
688                        throw new CmsIllegalArgumentException(
689                            Messages.get().container(Messages.ERR_INVALID_CONVERSION_SPEC_1, fmtArg));
690                    }
691                } else {
692                    throw new CmsIllegalArgumentException(
693                        Messages.get().container(Messages.ERR_INVALID_CONVERSION_SPEC_1, fmtArg));
694                }
695            } else {
696                throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_CONTROL_STRING_START_0));
697            }
698        }
699
700        /**
701         * Internal helper.<p>
702         *
703         * @return the result
704         */
705        int getArgumentPosition() {
706
707            return m_argumentPosition;
708        }
709
710        /**
711         * Internal helper.<p>
712         *
713         * @return the result
714         */
715        int getArgumentPositionForFieldWidth() {
716
717            return m_argumentPositionForFieldWidth;
718        }
719
720        /**
721         * Internal helper.<p>
722         *
723         * @return the result
724         */
725        int getArgumentPositionForPrecision() {
726
727            return m_argumentPositionForPrecision;
728        }
729
730        /**
731         * Get the conversion character that tells what
732         * type of control character this instance has.
733         *
734         * @return the conversion character.
735         */
736        char getConversionCharacter() {
737
738            return m_conversionCharacter;
739        }
740
741        /**
742         * Get the String for this instance.  Translate
743         * any escape sequences.
744         *
745         * @return s the stored String.
746         */
747        String getLiteral() {
748
749            StringBuffer sb = new StringBuffer();
750            int i = 0;
751            while (i < m_fmt.length()) {
752                if (m_fmt.charAt(i) == '\\') {
753                    i++;
754                    if (i < m_fmt.length()) {
755                        char c = m_fmt.charAt(i);
756                        switch (c) {
757                            case 'a':
758                                sb.append((char)0x07);
759                                break;
760                            case 'b':
761                                sb.append('\b');
762                                break;
763                            case 'f':
764                                sb.append('\f');
765                                break;
766                            case 'n':
767                                sb.append(System.getProperty("line.separator"));
768                                break;
769                            case 'r':
770                                sb.append('\r');
771                                break;
772                            case 't':
773                                sb.append('\t');
774                                break;
775                            case 'v':
776                                sb.append((char)0x0b);
777                                break;
778                            case '\\':
779                                sb.append('\\');
780                                break;
781                            default:
782                                // noop
783                        }
784                        i++;
785                    } else {
786                        sb.append('\\');
787                    }
788                } else {
789                    i++;
790                }
791            }
792            return m_fmt;
793        }
794
795        /**
796         * Format a double argument using this conversion
797         * specification.
798         * @param s the double to format.
799         * @return the formatted String.
800         * @exception CmsIllegalArgumentException if the
801         *     conversion character is c, C, s, S, i, d,
802         *     x, X, or o.
803         */
804        String internalsprintf(double s) throws CmsIllegalArgumentException {
805
806            String s2 = "";
807            switch (m_conversionCharacter) {
808                case 'f':
809                    s2 = printFFormat(s);
810                    break;
811                case 'E':
812                case 'e':
813                    s2 = printEFormat(s);
814                    break;
815                case 'G':
816                case 'g':
817                    s2 = printGFormat(s);
818                    break;
819                default:
820                    throw new CmsIllegalArgumentException(
821                        Messages.get().container(
822                            Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2,
823                            "double",
824                            Character.valueOf(m_conversionCharacter)));
825            }
826            return s2;
827        }
828
829        /**
830         * Format an int argument using this conversion
831         * specification.
832         * @param s the int to format.
833         * @return the formatted String.
834         * @exception CmsIllegalArgumentException if the
835         *     conversion character is f, e, E, g, or G.
836         */
837        String internalsprintf(int s) throws CmsIllegalArgumentException {
838
839            String s2 = "";
840            switch (m_conversionCharacter) {
841                case 'd':
842                case 'i':
843                    if (m_optionalh) {
844                        s2 = printDFormat((short)s);
845                    } else if (m_optionall) {
846                        s2 = printDFormat((long)s);
847                    } else {
848                        s2 = printDFormat(s);
849                    }
850                    break;
851                case 'x':
852                case 'X':
853                    if (m_optionalh) {
854                        s2 = printXFormat((short)s);
855                    } else if (m_optionall) {
856                        s2 = printXFormat((long)s);
857                    } else {
858                        s2 = printXFormat(s);
859                    }
860                    break;
861                case 'o':
862                    if (m_optionalh) {
863                        s2 = printOFormat((short)s);
864                    } else if (m_optionall) {
865                        s2 = printOFormat((long)s);
866                    } else {
867                        s2 = printOFormat(s);
868                    }
869                    break;
870                case 'c':
871                case 'C':
872                    s2 = printCFormat((char)s);
873                    break;
874                default:
875                    throw new CmsIllegalArgumentException(
876                        Messages.get().container(
877                            Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2,
878                            "int",
879                            Character.valueOf(m_conversionCharacter)));
880            }
881            return s2;
882        }
883
884        /**
885         * Format a long argument using this conversion
886         * specification.
887         * @param s the long to format.
888         * @return the formatted String.
889         * @exception CmsIllegalArgumentException if the
890         *     conversion character is f, e, E, g, or G.
891         */
892        String internalsprintf(long s) throws CmsIllegalArgumentException {
893
894            String s2 = "";
895            switch (m_conversionCharacter) {
896                case 'd':
897                case 'i':
898                    if (m_optionalh) {
899                        s2 = printDFormat((short)s);
900                    } else if (m_optionall) {
901                        s2 = printDFormat(s);
902                    } else {
903                        s2 = printDFormat((int)s);
904                    }
905                    break;
906                case 'x':
907                case 'X':
908                    if (m_optionalh) {
909                        s2 = printXFormat((short)s);
910                    } else if (m_optionall) {
911                        s2 = printXFormat(s);
912                    } else {
913                        s2 = printXFormat((int)s);
914                    }
915                    break;
916                case 'o':
917                    if (m_optionalh) {
918                        s2 = printOFormat((short)s);
919                    } else if (m_optionall) {
920                        s2 = printOFormat(s);
921                    } else {
922                        s2 = printOFormat((int)s);
923                    }
924                    break;
925                case 'c':
926                case 'C':
927                    s2 = printCFormat((char)s);
928                    break;
929                default:
930                    throw new CmsIllegalArgumentException(
931                        Messages.get().container(
932                            Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2,
933                            "long",
934                            Character.valueOf(m_conversionCharacter)));
935            }
936            return s2;
937        }
938
939        /**
940         * Format an Object argument using this conversion
941         * specification.
942         * @param s the Object to format.
943         * @return the formatted String.
944         * @exception CmsIllegalArgumentException if the
945         *     conversion character is neither s nor S.
946         */
947        String internalsprintf(Object s) throws CmsIllegalArgumentException {
948
949            String s2 = "";
950            if ((m_conversionCharacter == 's') || (m_conversionCharacter == 'S')) {
951                s2 = printSFormat(s.toString());
952            } else {
953                throw new CmsIllegalArgumentException(
954                    Messages.get().container(
955                        Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2,
956                        "String",
957                        Character.valueOf(m_conversionCharacter)));
958            }
959            return s2;
960        }
961
962        /**
963         * Format a String argument using this conversion
964         * specification.
965         * @param s the String to format.
966         * @return the formatted String.
967         * @exception CmsIllegalArgumentException if the
968         *   conversion character is neither s nor S.
969         */
970        String internalsprintf(String s) throws CmsIllegalArgumentException {
971
972            String s2 = "";
973            if ((m_conversionCharacter == 's') || (m_conversionCharacter == 'S')) {
974                s2 = printSFormat(s);
975            } else {
976                throw new CmsIllegalArgumentException(
977                    Messages.get().container(
978                        Messages.ERR_INVALID_DOUBLE_FMT_CHAR_2,
979                        "String",
980                        Character.valueOf(m_conversionCharacter)));
981            }
982            return s2;
983        }
984
985        /**
986         * Internal helper.<p>
987         *
988         * @return the result
989         */
990        boolean isPositionalFieldWidth() {
991
992            return m_positionalFieldWidth;
993        }
994
995        /**
996         * Internal helper.<p>
997         *
998         * @return the result
999         */
1000        boolean isPositionalPrecision() {
1001
1002            return m_positionalPrecision;
1003        }
1004
1005        /**
1006         * Internal helper.<p>
1007         *
1008         * @return the result
1009         */
1010        boolean isPositionalSpecification() {
1011
1012            return m_positionalSpecification;
1013        }
1014
1015        /**
1016         * Check whether the specifier has a variable
1017         * field width that is going to be set by an
1018         * argument.
1019         * @return <code>true</code> if the conversion
1020         *   uses an * field width; otherwise
1021         *   <code>false</code>.
1022         */
1023        boolean isVariableFieldWidth() {
1024
1025            return m_variableFieldWidth;
1026        }
1027
1028        /**
1029         * Check whether the specifier has a variable
1030         * precision that is going to be set by an
1031         * argument.
1032         * @return <code>true</code> if the conversion
1033         *   uses an * precision; otherwise
1034         *   <code>false</code>.
1035         */
1036        boolean isVariablePrecision() {
1037
1038            return m_variablePrecision;
1039        }
1040
1041        /**
1042         * Set the field width with an argument.  A
1043         * negative field width is taken as a - flag
1044         * followed by a positive field width.
1045         * @param fw the field width.
1046         */
1047        void setFieldWidthWithArg(int fw) {
1048
1049            if (fw < 0) {
1050                m_leftJustify = true;
1051            }
1052            m_fieldWidthSet = true;
1053            m_fieldWidth = Math.abs(fw);
1054        }
1055
1056        /**
1057         * Set the String for this instance.
1058         * @param s the String to store.
1059         */
1060        void setLiteral(String s) {
1061
1062            m_fmt = s;
1063        }
1064
1065        /**
1066         * Set the precision with an argument.  A
1067         * negative precision will be changed to zero.
1068         * @param pr the precision.
1069         */
1070        void setPrecisionWithArg(int pr) {
1071
1072            m_precisionSet = true;
1073            m_precision = Math.max(pr, 0);
1074        }
1075
1076        /**
1077         * Apply zero or blank, left or right padding.
1078         * @param ca4 array of characters before padding is
1079         *     finished
1080         * @param noDigits NaN or signed Inf
1081         * @return a padded array of characters
1082         */
1083        private char[] applyFloatPadding(char[] ca4, boolean noDigits) {
1084
1085            char[] ca5 = ca4;
1086            if (m_fieldWidthSet) {
1087                int i, j, nBlanks;
1088                if (m_leftJustify) {
1089                    nBlanks = m_fieldWidth - ca4.length;
1090                    if (nBlanks > 0) {
1091                        ca5 = new char[ca4.length + nBlanks];
1092                        for (i = 0; i < ca4.length; i++) {
1093                            ca5[i] = ca4[i];
1094                        }
1095                        for (j = 0; j < nBlanks; j++, i++) {
1096                            ca5[i] = ' ';
1097                        }
1098                    }
1099                } else if (!m_leadingZeros || noDigits) {
1100                    nBlanks = m_fieldWidth - ca4.length;
1101                    if (nBlanks > 0) {
1102                        ca5 = new char[ca4.length + nBlanks];
1103                        for (i = 0; i < nBlanks; i++) {
1104                            ca5[i] = ' ';
1105                        }
1106                        for (j = 0; j < ca4.length; i++, j++) {
1107                            ca5[i] = ca4[j];
1108                        }
1109                    }
1110                } else if (m_leadingZeros) {
1111                    nBlanks = m_fieldWidth - ca4.length;
1112                    if (nBlanks > 0) {
1113                        ca5 = new char[ca4.length + nBlanks];
1114                        i = 0;
1115                        j = 0;
1116                        if (ca4[0] == '-') {
1117                            ca5[0] = '-';
1118                            i++;
1119                            j++;
1120                        }
1121                        for (int k = 0; k < nBlanks; i++, k++) {
1122                            ca5[i] = '0';
1123                        }
1124                        for (; j < ca4.length; i++, j++) {
1125                            ca5[i] = ca4[j];
1126                        }
1127                    }
1128                }
1129            }
1130            return ca5;
1131        }
1132
1133        /**
1134         * Check to see if the digits that are going to
1135         * be truncated because of the precision should
1136         * force a round in the preceding digits.
1137         * @param ca1 the array of digits
1138         * @param icarry the index of the first digit that
1139         *     is to be truncated from the print
1140         * @return <code>true</code> if the truncation forces
1141         *     a round that will change the print
1142         */
1143        private boolean checkForCarry(char[] ca1, int icarry) {
1144
1145            boolean carry = false;
1146            if (icarry < ca1.length) {
1147                if ((ca1[icarry] == '6') || (ca1[icarry] == '7') || (ca1[icarry] == '8') || (ca1[icarry] == '9')) {
1148                    carry = true;
1149                } else if (ca1[icarry] == '5') {
1150                    int ii = icarry + 1;
1151                    for (; ii < ca1.length; ii++) {
1152                        if (ca1[ii] != '0') {
1153                            break;
1154                        }
1155                    }
1156                    carry = ii < ca1.length;
1157                    if (!carry && (icarry > 0)) {
1158                        carry = ((ca1[icarry - 1] == '1')
1159                            || (ca1[icarry - 1] == '3')
1160                            || (ca1[icarry - 1] == '5')
1161                            || (ca1[icarry - 1] == '7')
1162                            || (ca1[icarry - 1] == '9'));
1163                    }
1164                }
1165            }
1166            return carry;
1167        }
1168
1169        /**
1170         * For e format, the flag character '-', means that
1171         * the output should be left justified within the
1172         * field.  The default is to pad with blanks on the
1173         * left.  '+' character means that the conversion
1174         * will always begin with a sign (+ or -).  The
1175         * blank flag character means that a non-negative
1176         * input will be preceded with a blank.  If both a
1177         * '+' and a ' ' are specified, the blank flag is
1178         * ignored.  The '0' flag character implies that
1179         * padding to the field width will be done with
1180         * zeros instead of blanks.
1181         *
1182         * The field width is treated as the minimum number
1183         * of characters to be printed.  The default is to
1184         * add no padding.  Padding is with blanks by
1185         * default.
1186         *
1187         * The precision, if set, is the minimum number of
1188         * digits to appear after the radix character.
1189         * Padding is with trailing 0s.
1190         *
1191         * The behavior is like printf.  One (hopefully the
1192         * only) exception is that the minimum number of
1193         * exponent digits is 3 instead of 2 for e and E
1194         * formats when the optional L is used before the
1195         * e, E, g, or G conversion character. The optional
1196         * L does not imply conversion to a long long
1197         * double.
1198         *
1199         * @param x the x parameter
1200         * @param eChar the eChar parameter
1201         * @return the result
1202         */
1203        private char[] eFormatDigits(double x, char eChar) {
1204
1205            char[] ca1, ca2, ca3;
1206            // int defaultDigits=6;
1207            String sx;
1208            int i, j, k, p;
1209            int expon = 0;
1210            int ePos, rPos, eSize;
1211            boolean minusSign = false;
1212            if (x > 0.0) {
1213                sx = Double.toString(x);
1214            } else if (x < 0.0) {
1215                sx = Double.toString(-x);
1216                minusSign = true;
1217            } else {
1218                sx = Double.toString(x);
1219                if (sx.charAt(0) == '-') {
1220                    minusSign = true;
1221                    sx = sx.substring(1);
1222                }
1223            }
1224            ePos = sx.indexOf('E');
1225            if (ePos == -1) {
1226                ePos = sx.indexOf('e');
1227            }
1228            rPos = sx.indexOf('.');
1229            if (ePos != -1) {
1230                int ie = ePos + 1;
1231                expon = 0;
1232                if (sx.charAt(ie) == '-') {
1233                    for (++ie; ie < sx.length(); ie++) {
1234                        if (sx.charAt(ie) != '0') {
1235                            break;
1236                        }
1237                    }
1238                    if (ie < sx.length()) {
1239                        expon = -Integer.parseInt(sx.substring(ie));
1240                    }
1241                } else {
1242                    if (sx.charAt(ie) == '+') {
1243                        ++ie;
1244                    }
1245                    for (; ie < sx.length(); ie++) {
1246                        if (sx.charAt(ie) != '0') {
1247                            break;
1248                        }
1249                    }
1250                    if (ie < sx.length()) {
1251                        expon = Integer.parseInt(sx.substring(ie));
1252                    }
1253                }
1254            }
1255            if (rPos != -1) {
1256                expon += rPos - 1;
1257            }
1258            if (m_precisionSet) {
1259                p = m_precision;
1260            } else {
1261                p = DEFAULT_DIGITS - 1;
1262            }
1263            if ((rPos != -1) && (ePos != -1)) {
1264                ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray();
1265            } else if (rPos != -1) {
1266                ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray();
1267            } else if (ePos != -1) {
1268                ca1 = sx.substring(0, ePos).toCharArray();
1269            } else {
1270                ca1 = sx.toCharArray();
1271            }
1272            boolean carry = false;
1273            int i0 = 0;
1274            if (ca1[0] != '0') {
1275                i0 = 0;
1276            } else {
1277                for (i0 = 0; i0 < ca1.length; i0++) {
1278                    if (ca1[i0] != '0') {
1279                        break;
1280                    }
1281                }
1282            }
1283            if ((i0 + p) < (ca1.length - 1)) {
1284                carry = checkForCarry(ca1, i0 + p + 1);
1285                if (carry) {
1286                    carry = startSymbolicCarry(ca1, i0 + p, i0);
1287                }
1288                if (carry) {
1289                    ca2 = new char[i0 + p + 1];
1290                    ca2[i0] = '1';
1291                    for (j = 0; j < i0; j++) {
1292                        ca2[j] = '0';
1293                    }
1294                    for (i = i0, j = i0 + 1; j < (p + 1); i++, j++) {
1295                        ca2[j] = ca1[i];
1296                    }
1297                    expon++;
1298                    ca1 = ca2;
1299                }
1300            }
1301            if ((Math.abs(expon) < 100) && !m_optionalL) {
1302                eSize = 4;
1303            } else {
1304                eSize = 5;
1305            }
1306            if (m_alternateForm || !m_precisionSet || (m_precision != 0)) {
1307                ca2 = new char[2 + p + eSize];
1308            } else {
1309                ca2 = new char[1 + eSize];
1310            }
1311            if (ca1[0] != '0') {
1312                ca2[0] = ca1[0];
1313                j = 1;
1314            } else {
1315                for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++) {
1316                    if (ca1[j] != '0') {
1317                        break;
1318                    }
1319                }
1320                if (((ePos != -1) && (j < ePos)) || ((ePos == -1) && (j < ca1.length))) {
1321                    ca2[0] = ca1[j];
1322                    expon -= j;
1323                    j++;
1324                } else {
1325                    ca2[0] = '0';
1326                    j = 2;
1327                }
1328            }
1329            if (m_alternateForm || !m_precisionSet || (m_precision != 0)) {
1330                ca2[1] = '.';
1331                i = 2;
1332            } else {
1333                i = 1;
1334            }
1335            for (k = 0; (k < p) && (j < ca1.length); j++, i++, k++) {
1336                ca2[i] = ca1[j];
1337            }
1338            for (; i < (ca2.length - eSize); i++) {
1339                ca2[i] = '0';
1340            }
1341            ca2[i++] = eChar;
1342            if (expon < 0) {
1343                ca2[i++] = '-';
1344            } else {
1345                ca2[i++] = '+';
1346            }
1347            expon = Math.abs(expon);
1348            if (expon >= 100) {
1349                switch (expon / 100) {
1350                    case 1:
1351                        ca2[i] = '1';
1352                        break;
1353                    case 2:
1354                        ca2[i] = '2';
1355                        break;
1356                    case 3:
1357                        ca2[i] = '3';
1358                        break;
1359                    case 4:
1360                        ca2[i] = '4';
1361                        break;
1362                    case 5:
1363                        ca2[i] = '5';
1364                        break;
1365                    case 6:
1366                        ca2[i] = '6';
1367                        break;
1368                    case 7:
1369                        ca2[i] = '7';
1370                        break;
1371                    case 8:
1372                        ca2[i] = '8';
1373                        break;
1374                    case 9:
1375                        ca2[i] = '9';
1376                        break;
1377                    default:
1378                        // noop
1379                }
1380                i++;
1381            }
1382            switch ((expon % 100) / 10) {
1383                case 0:
1384                    ca2[i] = '0';
1385                    break;
1386                case 1:
1387                    ca2[i] = '1';
1388                    break;
1389                case 2:
1390                    ca2[i] = '2';
1391                    break;
1392                case 3:
1393                    ca2[i] = '3';
1394                    break;
1395                case 4:
1396                    ca2[i] = '4';
1397                    break;
1398                case 5:
1399                    ca2[i] = '5';
1400                    break;
1401                case 6:
1402                    ca2[i] = '6';
1403                    break;
1404                case 7:
1405                    ca2[i] = '7';
1406                    break;
1407                case 8:
1408                    ca2[i] = '8';
1409                    break;
1410                case 9:
1411                    ca2[i] = '9';
1412                    break;
1413                default:
1414                    // noop
1415            }
1416            i++;
1417            switch (expon % 10) {
1418                case 0:
1419                    ca2[i] = '0';
1420                    break;
1421                case 1:
1422                    ca2[i] = '1';
1423                    break;
1424                case 2:
1425                    ca2[i] = '2';
1426                    break;
1427                case 3:
1428                    ca2[i] = '3';
1429                    break;
1430                case 4:
1431                    ca2[i] = '4';
1432                    break;
1433                case 5:
1434                    ca2[i] = '5';
1435                    break;
1436                case 6:
1437                    ca2[i] = '6';
1438                    break;
1439                case 7:
1440                    ca2[i] = '7';
1441                    break;
1442                case 8:
1443                    ca2[i] = '8';
1444                    break;
1445                case 9:
1446                    ca2[i] = '9';
1447                    break;
1448                default:
1449                    // noop
1450            }
1451            int nZeros = 0;
1452            if (!m_leftJustify && m_leadingZeros) {
1453                int xThousands = 0;
1454                if (m_thousands) {
1455                    int xlead = 0;
1456                    if ((ca2[0] == '+') || (ca2[0] == '-') || (ca2[0] == ' ')) {
1457                        xlead = 1;
1458                    }
1459                    int xdp = xlead;
1460                    for (; xdp < ca2.length; xdp++) {
1461                        if (ca2[xdp] == '.') {
1462                            break;
1463                        }
1464                    }
1465                    xThousands = (xdp - xlead) / 3;
1466                }
1467                if (m_fieldWidthSet) {
1468                    nZeros = m_fieldWidth - ca2.length;
1469                }
1470                if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) {
1471                    nZeros--;
1472                }
1473                nZeros -= xThousands;
1474                if (nZeros < 0) {
1475                    nZeros = 0;
1476                }
1477            }
1478            j = 0;
1479            if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) {
1480                ca3 = new char[ca2.length + nZeros + 1];
1481                j++;
1482            } else {
1483                ca3 = new char[ca2.length + nZeros];
1484            }
1485            if (!minusSign) {
1486                if (m_leadingSign) {
1487                    ca3[0] = '+';
1488                }
1489                if (m_leadingSpace) {
1490                    ca3[0] = ' ';
1491                }
1492            } else {
1493                ca3[0] = '-';
1494            }
1495            for (k = 0; k < nZeros; j++, k++) {
1496                ca3[j] = '0';
1497            }
1498            for (i = 0; (i < ca2.length) && (j < ca3.length); i++, j++) {
1499                ca3[j] = ca2[i];
1500            }
1501
1502            int lead = 0;
1503            if ((ca3[0] == '+') || (ca3[0] == '-') || (ca3[0] == ' ')) {
1504                lead = 1;
1505            }
1506            int dp = lead;
1507            for (; dp < ca3.length; dp++) {
1508                if (ca3[dp] == '.') {
1509                    break;
1510                }
1511            }
1512            int nThousands = dp / 3;
1513            // Localize the decimal point.
1514            if (dp < ca3.length) {
1515                ca3[dp] = m_dfs.getDecimalSeparator();
1516            }
1517            char[] ca4 = ca3;
1518            if (m_thousands && (nThousands > 0)) {
1519                ca4 = new char[ca3.length + nThousands + lead];
1520                ca4[0] = ca3[0];
1521                for (i = lead, k = lead; i < dp; i++) {
1522                    if ((i > 0) && (((dp - i) % 3) == 0)) {
1523                        // ca4[k]=',';
1524                        ca4[k] = m_dfs.getGroupingSeparator();
1525                        ca4[k + 1] = ca3[i];
1526                        k += 2;
1527                    } else {
1528                        ca4[k] = ca3[i];
1529                        k++;
1530                    }
1531                }
1532                for (; i < ca3.length; i++, k++) {
1533                    ca4[k] = ca3[i];
1534                }
1535            }
1536            return ca4;
1537        }
1538
1539        /**
1540         * An intermediate routine on the way to creating
1541         * an e format String.  The method decides whether
1542         * the input double value is an infinity,
1543         * not-a-number, or a finite double and formats
1544         * each type of input appropriately.
1545         * @param x the double value to be formatted.
1546         * @param eChar an 'e' or 'E' to use in the
1547         *     converted double value.
1548         * @return the converted double value.
1549         */
1550        private String eFormatString(double x, char eChar) {
1551
1552            char[] ca4, ca5;
1553            if (Double.isInfinite(x)) {
1554                if (x == Double.POSITIVE_INFINITY) {
1555                    if (m_leadingSign) {
1556                        ca4 = "+Inf".toCharArray();
1557                    } else if (m_leadingSpace) {
1558                        ca4 = " Inf".toCharArray();
1559                    } else {
1560                        ca4 = "Inf".toCharArray();
1561                    }
1562                } else {
1563                    ca4 = "-Inf".toCharArray();
1564                }
1565            } else if (Double.isNaN(x)) {
1566                if (m_leadingSign) {
1567                    ca4 = "+NaN".toCharArray();
1568                } else if (m_leadingSpace) {
1569                    ca4 = " NaN".toCharArray();
1570                } else {
1571                    ca4 = "NaN".toCharArray();
1572                }
1573            } else {
1574                ca4 = eFormatDigits(x, eChar);
1575            }
1576            ca5 = applyFloatPadding(ca4, false);
1577            return new String(ca5);
1578        }
1579
1580        /**
1581         * For f format, the flag character '-', means that
1582         * the output should be left justified within the
1583         * field.  The default is to pad with blanks on the
1584         * left.  '+' character means that the conversion
1585         * will always begin with a sign (+ or -).  The
1586         * blank flag character means that a non-negative
1587         * input will be preceded with a blank.  If both
1588         * a '+' and a ' ' are specified, the blank flag
1589         * is ignored.  The '0' flag character implies that
1590         * padding to the field width will be done with
1591         * zeros instead of blanks.
1592         *
1593         * The field width is treated as the minimum number
1594         * of characters to be printed.  The default is to
1595         * add no padding.  Padding is with blanks by
1596         * default.
1597         *
1598         * The precision, if set, is the number of digits
1599         * to appear after the radix character.  Padding is
1600         * with trailing 0s.
1601         *
1602         * @param x the paramater
1603         * @return the result
1604         */
1605        private char[] fFormatDigits(double x) {
1606
1607            // int defaultDigits=6;
1608            String sx;
1609            int i, j, k;
1610            int n1In, n2In;
1611            int expon = 0;
1612            boolean minusSign = false;
1613            if (x > 0.0) {
1614                sx = Double.toString(x);
1615            } else if (x < 0.0) {
1616                sx = Double.toString(-x);
1617                minusSign = true;
1618            } else {
1619                sx = Double.toString(x);
1620                if (sx.charAt(0) == '-') {
1621                    minusSign = true;
1622                    sx = sx.substring(1);
1623                }
1624            }
1625            int ePos = sx.indexOf('E');
1626            int rPos = sx.indexOf('.');
1627            if (rPos != -1) {
1628                n1In = rPos;
1629            } else if (ePos != -1) {
1630                n1In = ePos;
1631            } else {
1632                n1In = sx.length();
1633            }
1634            if (rPos != -1) {
1635                if (ePos != -1) {
1636                    n2In = ePos - rPos - 1;
1637                } else {
1638                    n2In = sx.length() - rPos - 1;
1639                }
1640            } else {
1641                n2In = 0;
1642            }
1643            if (ePos != -1) {
1644                int ie = ePos + 1;
1645                expon = 0;
1646                if (sx.charAt(ie) == '-') {
1647                    for (++ie; ie < sx.length(); ie++) {
1648                        if (sx.charAt(ie) != '0') {
1649                            break;
1650                        }
1651                    }
1652                    if (ie < sx.length()) {
1653                        expon = -Integer.parseInt(sx.substring(ie));
1654                    }
1655                } else {
1656                    if (sx.charAt(ie) == '+') {
1657                        ++ie;
1658                    }
1659                    for (; ie < sx.length(); ie++) {
1660                        if (sx.charAt(ie) != '0') {
1661                            break;
1662                        }
1663                    }
1664                    if (ie < sx.length()) {
1665                        expon = Integer.parseInt(sx.substring(ie));
1666                    }
1667                }
1668            }
1669            int p;
1670            if (m_precisionSet) {
1671                p = m_precision;
1672            } else {
1673                p = DEFAULT_DIGITS - 1;
1674            }
1675            char[] ca1 = sx.toCharArray();
1676            char[] ca2 = new char[n1In + n2In];
1677            char[] ca3, ca4, ca5;
1678            for (j = 0; j < n1In; j++) {
1679                ca2[j] = ca1[j];
1680            }
1681            i = j + 1;
1682            for (k = 0; k < n2In; j++, i++, k++) {
1683                ca2[j] = ca1[i];
1684            }
1685            if ((n1In + expon) <= 0) {
1686                ca3 = new char[-expon + n2In];
1687                for (j = 0, k = 0; k < (-n1In - expon); k++, j++) {
1688                    ca3[j] = '0';
1689                }
1690                for (i = 0; i < (n1In + n2In); i++, j++) {
1691                    ca3[j] = ca2[i];
1692                }
1693            } else {
1694                ca3 = ca2;
1695            }
1696            boolean carry = false;
1697            if (p < (-expon + n2In)) {
1698                if (expon < 0) {
1699                    i = p;
1700                } else {
1701                    i = p + n1In;
1702                }
1703                carry = checkForCarry(ca3, i);
1704                if (carry) {
1705                    carry = startSymbolicCarry(ca3, i - 1, 0);
1706                }
1707            }
1708            if ((n1In + expon) <= 0) {
1709                ca4 = new char[2 + p];
1710                if (!carry) {
1711                    ca4[0] = '0';
1712                } else {
1713                    ca4[0] = '1';
1714                }
1715                if (m_alternateForm || !m_precisionSet || (m_precision != 0)) {
1716                    ca4[1] = '.';
1717                    for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++) {
1718                        ca4[j] = ca3[i];
1719                    }
1720                    for (; j < ca4.length; j++) {
1721                        ca4[j] = '0';
1722                    }
1723                }
1724            } else {
1725                if (!carry) {
1726                    if (m_alternateForm || !m_precisionSet || (m_precision != 0)) {
1727                        ca4 = new char[n1In + expon + p + 1];
1728                    } else {
1729                        ca4 = new char[n1In + expon];
1730                    }
1731                    j = 0;
1732                } else {
1733                    if (m_alternateForm || !m_precisionSet || (m_precision != 0)) {
1734                        ca4 = new char[n1In + expon + p + 2];
1735                    } else {
1736                        ca4 = new char[n1In + expon + 1];
1737                    }
1738                    ca4[0] = '1';
1739                    j = 1;
1740                }
1741                for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++) {
1742                    ca4[j] = ca3[i];
1743                }
1744                for (; i < (n1In + expon); i++, j++) {
1745                    ca4[j] = '0';
1746                }
1747                if (m_alternateForm || !m_precisionSet || (m_precision != 0)) {
1748                    ca4[j] = '.';
1749                    j++;
1750                    for (k = 0; (i < ca3.length) && (k < p); i++, j++, k++) {
1751                        ca4[j] = ca3[i];
1752                    }
1753                    for (; j < ca4.length; j++) {
1754                        ca4[j] = '0';
1755                    }
1756                }
1757            }
1758            int nZeros = 0;
1759            if (!m_leftJustify && m_leadingZeros) {
1760                int xThousands = 0;
1761                if (m_thousands) {
1762                    int xlead = 0;
1763                    if ((ca4[0] == '+') || (ca4[0] == '-') || (ca4[0] == ' ')) {
1764                        xlead = 1;
1765                    }
1766                    int xdp = xlead;
1767                    for (; xdp < ca4.length; xdp++) {
1768                        if (ca4[xdp] == '.') {
1769                            break;
1770                        }
1771                    }
1772                    xThousands = (xdp - xlead) / 3;
1773                }
1774                if (m_fieldWidthSet) {
1775                    nZeros = m_fieldWidth - ca4.length;
1776                }
1777                if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) {
1778                    nZeros--;
1779                }
1780                nZeros -= xThousands;
1781                if (nZeros < 0) {
1782                    nZeros = 0;
1783                }
1784            }
1785            j = 0;
1786            if ((!minusSign && (m_leadingSign || m_leadingSpace)) || minusSign) {
1787                ca5 = new char[ca4.length + nZeros + 1];
1788                j++;
1789            } else {
1790                ca5 = new char[ca4.length + nZeros];
1791            }
1792            if (!minusSign) {
1793                if (m_leadingSign) {
1794                    ca5[0] = '+';
1795                }
1796                if (m_leadingSpace) {
1797                    ca5[0] = ' ';
1798                }
1799            } else {
1800                ca5[0] = '-';
1801            }
1802            for (i = 0; i < nZeros; i++, j++) {
1803                ca5[j] = '0';
1804            }
1805            for (i = 0; i < ca4.length; i++, j++) {
1806                ca5[j] = ca4[i];
1807            }
1808            int lead = 0;
1809            if ((ca5[0] == '+') || (ca5[0] == '-') || (ca5[0] == ' ')) {
1810                lead = 1;
1811            }
1812            int dp = lead;
1813            for (; dp < ca5.length; dp++) {
1814                if (ca5[dp] == '.') {
1815                    break;
1816                }
1817            }
1818            int nThousands = (dp - lead) / 3;
1819            // Localize the decimal point.
1820            if (dp < ca5.length) {
1821                ca5[dp] = m_dfs.getDecimalSeparator();
1822            }
1823            char[] ca6 = ca5;
1824            if (m_thousands && (nThousands > 0)) {
1825                ca6 = new char[ca5.length + nThousands + lead];
1826                ca6[0] = ca5[0];
1827                for (i = lead, k = lead; i < dp; i++) {
1828                    if ((i > 0) && (((dp - i) % 3) == 0)) {
1829                        // ca6[k]=',';
1830                        ca6[k] = m_dfs.getGroupingSeparator();
1831                        ca6[k + 1] = ca5[i];
1832                        k += 2;
1833                    } else {
1834                        ca6[k] = ca5[i];
1835                        k++;
1836                    }
1837                }
1838                for (; i < ca5.length; i++, k++) {
1839                    ca6[k] = ca5[i];
1840                }
1841            }
1842            return ca6;
1843        }
1844
1845        /**
1846         * An intermediate routine on the way to creating
1847         * an f format String.  The method decides whether
1848         * the input double value is an infinity,
1849         * not-a-number, or a finite double and formats
1850         * each type of input appropriately.
1851         * @param x the double value to be formatted.
1852         * @return the converted double value.
1853         */
1854        private String fFormatString(double x) {
1855
1856            char[] ca6, ca7;
1857            if (Double.isInfinite(x)) {
1858                if (x == Double.POSITIVE_INFINITY) {
1859                    if (m_leadingSign) {
1860                        ca6 = "+Inf".toCharArray();
1861                    } else if (m_leadingSpace) {
1862                        ca6 = " Inf".toCharArray();
1863                    } else {
1864                        ca6 = "Inf".toCharArray();
1865                    }
1866                } else {
1867                    ca6 = "-Inf".toCharArray();
1868                }
1869            } else if (Double.isNaN(x)) {
1870                if (m_leadingSign) {
1871                    ca6 = "+NaN".toCharArray();
1872                } else if (m_leadingSpace) {
1873                    ca6 = " NaN".toCharArray();
1874                } else {
1875                    ca6 = "NaN".toCharArray();
1876                }
1877            } else {
1878                ca6 = fFormatDigits(x);
1879            }
1880            ca7 = applyFloatPadding(ca6, false);
1881            return new String(ca7);
1882        }
1883
1884        /**
1885         * Format method for the c conversion character and
1886         * char argument.
1887         *
1888         * The only flag character that affects c format is
1889         * the '-', meaning that the output should be left
1890         * justified within the field.  The default is to
1891         * pad with blanks on the left.
1892         *
1893         * The field width is treated as the minimum number
1894         * of characters to be printed.  Padding is with
1895         * blanks by default.  The default width is 1.
1896         *
1897         * The precision, if set, is ignored.
1898         * @param x the char to format.
1899         * @return the formatted String.
1900         */
1901        private String printCFormat(char x) {
1902
1903            int nPrint = 1;
1904            int width = m_fieldWidth;
1905            if (!m_fieldWidthSet) {
1906                width = nPrint;
1907            }
1908            char[] ca = new char[width];
1909            int i = 0;
1910            if (m_leftJustify) {
1911                ca[0] = x;
1912                for (i = 1; i <= (width - nPrint); i++) {
1913                    ca[i] = ' ';
1914                }
1915            } else {
1916                for (i = 0; i < (width - nPrint); i++) {
1917                    ca[i] = ' ';
1918                }
1919                ca[i] = x;
1920            }
1921            return new String(ca);
1922        }
1923
1924        /**
1925         * Format method for the d conversion character and
1926         * int argument.
1927         *
1928         * For d format, the flag character '-', means that
1929         * the output should be left justified within the
1930         * field.  The default is to pad with blanks on the
1931         * left.  A '+' character means that the conversion
1932         * will always begin with a sign (+ or -).  The
1933         * blank flag character means that a non-negative
1934         * input will be preceded with a blank.  If both a
1935         * '+' and a ' ' are specified, the blank flag is
1936         * ignored.  The '0' flag character implies that
1937         * padding to the field width will be done with
1938         * zeros instead of blanks.
1939         *
1940         * The field width is treated as the minimum number
1941         * of characters to be printed.  The default is to
1942         * add no padding.  Padding is with blanks by
1943         * default.
1944         *
1945         * The precision, if set, is the minimum number of
1946         * digits to appear.  Padding is with leading 0s.
1947         * @param x the int to format.
1948         * @return the formatted String.
1949         */
1950        private String printDFormat(int x) {
1951
1952            return printDFormat(Integer.toString(x));
1953        }
1954
1955        /**
1956         * Format method for the d conversion character and
1957         * long argument.
1958         *
1959         * For d format, the flag character '-', means that
1960         * the output should be left justified within the
1961         * field.  The default is to pad with blanks on the
1962         * left.  A '+' character means that the conversion
1963         * will always begin with a sign (+ or -).  The
1964         * blank flag character means that a non-negative
1965         * input will be preceded with a blank.  If both a
1966         * '+' and a ' ' are specified, the blank flag is
1967         * ignored.  The '0' flag character implies that
1968         * padding to the field width will be done with
1969         * zeros instead of blanks.
1970         *
1971         * The field width is treated as the minimum number
1972         * of characters to be printed.  The default is to
1973         * add no padding.  Padding is with blanks by
1974         * default.
1975         *
1976         * The precision, if set, is the minimum number of
1977         * digits to appear.  Padding is with leading 0s.
1978         * @param x the long to format.
1979         * @return the formatted String.
1980         */
1981        private String printDFormat(long x) {
1982
1983            return printDFormat(Long.toString(x));
1984        }
1985
1986        /**
1987         * Format method for the d conversion specifer and
1988         * short argument.
1989         *
1990         * For d format, the flag character '-', means that
1991         * the output should be left justified within the
1992         * field.  The default is to pad with blanks on the
1993         * left.  A '+' character means that the conversion
1994         * will always begin with a sign (+ or -).  The
1995         * blank flag character means that a non-negative
1996         * input will be preceded with a blank.  If both a
1997         * '+' and a ' ' are specified, the blank flag is
1998         * ignored.  The '0' flag character implies that
1999         * padding to the field width will be done with
2000         * zeros instead of blanks.
2001         *
2002         * The field width is treated as the minimum number
2003         * of characters to be printed.  The default is to
2004         * add no padding.  Padding is with blanks by
2005         * default.
2006         *
2007         * The precision, if set, is the minimum number of
2008         * digits to appear.  Padding is with leading 0s.
2009         * @param x the short to format.
2010         * @return the formatted String.
2011         */
2012        private String printDFormat(short x) {
2013
2014            return printDFormat(Short.toString(x));
2015        }
2016
2017        /**
2018         * Utility method for formatting using the d
2019         * conversion character.
2020         * @param sx the String to format, the result of
2021         *     converting a short, int, or long to a
2022         *     String.
2023         * @return the formatted String.
2024         */
2025        private String printDFormat(String sx) {
2026
2027            int nLeadingZeros = 0;
2028            int nBlanks = 0, n = 0;
2029            int i = 0, jFirst = 0;
2030            boolean neg = sx.charAt(0) == '-';
2031            if (sx.equals("0") && m_precisionSet && (m_precision == 0)) {
2032                sx = "";
2033            }
2034            if (!neg) {
2035                if (m_precisionSet && (sx.length() < m_precision)) {
2036                    nLeadingZeros = m_precision - sx.length();
2037                }
2038            } else {
2039                if (m_precisionSet && ((sx.length() - 1) < m_precision)) {
2040                    nLeadingZeros = (m_precision - sx.length()) + 1;
2041                }
2042            }
2043            if (nLeadingZeros < 0) {
2044                nLeadingZeros = 0;
2045            }
2046            if (m_fieldWidthSet) {
2047                nBlanks = m_fieldWidth - nLeadingZeros - sx.length();
2048                if (!neg && (m_leadingSign || m_leadingSpace)) {
2049                    nBlanks--;
2050                }
2051            }
2052            if (nBlanks < 0) {
2053                nBlanks = 0;
2054            }
2055            if (m_leadingSign) {
2056                n++;
2057            } else if (m_leadingSpace) {
2058                n++;
2059            }
2060            n += nBlanks;
2061            n += nLeadingZeros;
2062            n += sx.length();
2063            char[] ca = new char[n];
2064            if (m_leftJustify) {
2065                if (neg) {
2066                    ca[i++] = '-';
2067                } else if (m_leadingSign) {
2068                    ca[i++] = '+';
2069                } else if (m_leadingSpace) {
2070                    ca[i++] = ' ';
2071                }
2072                char[] csx = sx.toCharArray();
2073                jFirst = neg ? 1 : 0;
2074                for (int j = 0; j < nLeadingZeros; i++, j++) {
2075                    ca[i] = '0';
2076                }
2077                for (int j = jFirst; j < csx.length; j++, i++) {
2078                    ca[i] = csx[j];
2079                }
2080                for (int j = 0; j < nBlanks; i++, j++) {
2081                    ca[i] = ' ';
2082                }
2083            } else {
2084                if (!m_leadingZeros) {
2085                    for (i = 0; i < nBlanks; i++) {
2086                        ca[i] = ' ';
2087                    }
2088                    if (neg) {
2089                        ca[i++] = '-';
2090                    } else if (m_leadingSign) {
2091                        ca[i++] = '+';
2092                    } else if (m_leadingSpace) {
2093                        ca[i++] = ' ';
2094                    }
2095                } else {
2096                    if (neg) {
2097                        ca[i++] = '-';
2098                    } else if (m_leadingSign) {
2099                        ca[i++] = '+';
2100                    } else if (m_leadingSpace) {
2101                        ca[i++] = ' ';
2102                    }
2103                    for (int j = 0; j < nBlanks; j++, i++) {
2104                        ca[i] = '0';
2105                    }
2106                }
2107                for (int j = 0; j < nLeadingZeros; j++, i++) {
2108                    ca[i] = '0';
2109                }
2110                char[] csx = sx.toCharArray();
2111                jFirst = neg ? 1 : 0;
2112                for (int j = jFirst; j < csx.length; j++, i++) {
2113                    ca[i] = csx[j];
2114                }
2115            }
2116            return new String(ca);
2117        }
2118
2119        /**
2120         * Format method for the e or E conversion
2121         * character.
2122         * @param x the double to format.
2123         * @return the formatted String.
2124         */
2125        private String printEFormat(double x) {
2126
2127            if (m_conversionCharacter == 'e') {
2128                return eFormatString(x, 'e');
2129            } else {
2130                return eFormatString(x, 'E');
2131            }
2132        }
2133
2134        /**
2135         * Format method for the f conversion character.
2136         * @param x the double to format.
2137         * @return the formatted String.
2138         */
2139        private String printFFormat(double x) {
2140
2141            return fFormatString(x);
2142        }
2143
2144        /**
2145         * Format method for the g conversion character.
2146         *
2147         * For g format, the flag character '-', means that
2148         *  the output should be left justified within the
2149         * field.  The default is to pad with blanks on the
2150         * left.  '+' character means that the conversion
2151         * will always begin with a sign (+ or -).  The
2152         * blank flag character means that a non-negative
2153         * input will be preceded with a blank.  If both a
2154         * '+' and a ' ' are specified, the blank flag is
2155         * ignored.  The '0' flag character implies that
2156         * padding to the field width will be done with
2157         * zeros instead of blanks.
2158         *
2159         * The field width is treated as the minimum number
2160         * of characters to be printed.  The default is to
2161         * add no padding.  Padding is with blanks by
2162         * default.
2163         *
2164         * The precision, if set, is the minimum number of
2165         * digits to appear after the radix character.
2166         * Padding is with trailing 0s.
2167         * @param x the double to format.
2168         * @return the formatted String.
2169         */
2170        private String printGFormat(double x) {
2171
2172            String sx, sy, sz, ret;
2173            int savePrecision = m_precision;
2174            int i;
2175            char[] ca4, ca5;
2176            if (Double.isInfinite(x)) {
2177                if (x == Double.POSITIVE_INFINITY) {
2178                    if (m_leadingSign) {
2179                        ca4 = "+Inf".toCharArray();
2180                    } else if (m_leadingSpace) {
2181                        ca4 = " Inf".toCharArray();
2182                    } else {
2183                        ca4 = "Inf".toCharArray();
2184                    }
2185                } else {
2186                    ca4 = "-Inf".toCharArray();
2187                }
2188            } else if (Double.isNaN(x)) {
2189                if (m_leadingSign) {
2190                    ca4 = "+NaN".toCharArray();
2191                } else if (m_leadingSpace) {
2192                    ca4 = " NaN".toCharArray();
2193                } else {
2194                    ca4 = "NaN".toCharArray();
2195                }
2196            } else {
2197                if (!m_precisionSet) {
2198                    m_precision = DEFAULT_DIGITS;
2199                }
2200                if (m_precision == 0) {
2201                    m_precision = 1;
2202                }
2203                int ePos = -1;
2204                if (m_conversionCharacter == 'g') {
2205                    sx = eFormatString(x, 'e').trim();
2206                    ePos = sx.indexOf('e');
2207                } else {
2208                    sx = eFormatString(x, 'E').trim();
2209                    ePos = sx.indexOf('E');
2210                }
2211                i = ePos + 1;
2212                int expon = 0;
2213                if (sx.charAt(i) == '-') {
2214                    for (++i; i < sx.length(); i++) {
2215                        if (sx.charAt(i) != '0') {
2216                            break;
2217                        }
2218                    }
2219                    if (i < sx.length()) {
2220                        expon = -Integer.parseInt(sx.substring(i));
2221                    }
2222                } else {
2223                    if (sx.charAt(i) == '+') {
2224                        ++i;
2225                    }
2226                    for (; i < sx.length(); i++) {
2227                        if (sx.charAt(i) != '0') {
2228                            break;
2229                        }
2230                    }
2231                    if (i < sx.length()) {
2232                        expon = Integer.parseInt(sx.substring(i));
2233                    }
2234                }
2235                // Trim trailing zeros.
2236                // If the radix character is not followed by
2237                // a digit, trim it, too.
2238                if (!m_alternateForm) {
2239                    if ((expon >= -4) && (expon < m_precision)) {
2240                        sy = fFormatString(x).trim();
2241                    } else {
2242                        sy = sx.substring(0, ePos);
2243                    }
2244                    i = sy.length() - 1;
2245                    for (; i >= 0; i--) {
2246                        if (sy.charAt(i) != '0') {
2247                            break;
2248                        }
2249                    }
2250                    if ((i >= 0) && (sy.charAt(i) == '.')) {
2251                        i--;
2252                    }
2253                    if (i == -1) {
2254                        sz = "0";
2255                    } else if (!Character.isDigit(sy.charAt(i))) {
2256                        sz = sy.substring(0, i + 1) + "0";
2257                    } else {
2258                        sz = sy.substring(0, i + 1);
2259                    }
2260                    if ((expon >= -4) && (expon < m_precision)) {
2261                        ret = sz;
2262                    } else {
2263                        ret = sz + sx.substring(ePos);
2264                    }
2265                } else {
2266                    if ((expon >= -4) && (expon < m_precision)) {
2267                        ret = fFormatString(x).trim();
2268                    } else {
2269                        ret = sx;
2270                    }
2271                }
2272                // leading space was trimmed off during
2273                // construction
2274                if (m_leadingSpace) {
2275                    if (x >= 0) {
2276                        ret = " " + ret;
2277                    }
2278                }
2279                ca4 = ret.toCharArray();
2280            }
2281            // Pad with blanks or zeros.
2282            ca5 = applyFloatPadding(ca4, false);
2283            m_precision = savePrecision;
2284            return new String(ca5);
2285        }
2286
2287        /**
2288         * Format method for the o conversion character and
2289         * int argument.
2290         *
2291         * For o format, the flag character '-', means that
2292         * the output should be left justified within the
2293         * field.  The default is to pad with blanks on the
2294         * left.  The '#' flag character means that the
2295         * output begins with a leading 0 and the precision
2296         * is increased by 1.
2297         *
2298         * The field width is treated as the minimum number
2299         * of characters to be printed.  The default is to
2300         * add no padding.  Padding is with blanks by
2301         * default.
2302         *
2303         * The precision, if set, is the minimum number of
2304         * digits to appear.  Padding is with leading 0s.
2305         * @param x the int to format.
2306         * @return the formatted String.
2307         */
2308        private String printOFormat(int x) {
2309
2310            String sx = null;
2311            if (x == Integer.MIN_VALUE) {
2312                sx = "20000000000";
2313            } else if (x < 0) {
2314                String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8);
2315                switch (t.length()) {
2316                    case 1:
2317                        sx = "2000000000" + t;
2318                        break;
2319                    case 2:
2320                        sx = "200000000" + t;
2321                        break;
2322                    case 3:
2323                        sx = "20000000" + t;
2324                        break;
2325                    case 4:
2326                        sx = "2000000" + t;
2327                        break;
2328                    case 5:
2329                        sx = "200000" + t;
2330                        break;
2331                    case 6:
2332                        sx = "20000" + t;
2333                        break;
2334                    case 7:
2335                        sx = "2000" + t;
2336                        break;
2337                    case 8:
2338                        sx = "200" + t;
2339                        break;
2340                    case 9:
2341                        sx = "20" + t;
2342                        break;
2343                    case 10:
2344                        sx = "2" + t;
2345                        break;
2346                    case 11:
2347                        sx = "3" + t.substring(1);
2348                        break;
2349                    default:
2350                        // noop
2351                }
2352            } else {
2353                sx = Integer.toString(x, 8);
2354            }
2355            return printOFormat(sx);
2356        }
2357
2358        /**
2359         * Format method for the o conversion character and
2360         * long argument.
2361         *
2362         * For o format, the flag character '-', means that
2363         * the output should be left justified within the
2364         * field.  The default is to pad with blanks on the
2365         * left.  The '#' flag character means that the
2366         * output begins with a leading 0 and the precision
2367         * is increased by 1.
2368         *
2369         * The field width is treated as the minimum number
2370         * of characters to be printed.  The default is to
2371         * add no padding.  Padding is with blanks by
2372         * default.
2373         *
2374         * The precision, if set, is the minimum number of
2375         * digits to appear.  Padding is with leading 0s.
2376         * @param x the long to format.
2377         * @return the formatted String.
2378         */
2379        private String printOFormat(long x) {
2380
2381            String sx = null;
2382            if (x == Long.MIN_VALUE) {
2383                sx = "1000000000000000000000";
2384            } else if (x < 0) {
2385                String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8);
2386                switch (t.length()) {
2387                    case 1:
2388                        sx = "100000000000000000000" + t;
2389                        break;
2390                    case 2:
2391                        sx = "10000000000000000000" + t;
2392                        break;
2393                    case 3:
2394                        sx = "1000000000000000000" + t;
2395                        break;
2396                    case 4:
2397                        sx = "100000000000000000" + t;
2398                        break;
2399                    case 5:
2400                        sx = "10000000000000000" + t;
2401                        break;
2402                    case 6:
2403                        sx = "1000000000000000" + t;
2404                        break;
2405                    case 7:
2406                        sx = "100000000000000" + t;
2407                        break;
2408                    case 8:
2409                        sx = "10000000000000" + t;
2410                        break;
2411                    case 9:
2412                        sx = "1000000000000" + t;
2413                        break;
2414                    case 10:
2415                        sx = "100000000000" + t;
2416                        break;
2417                    case 11:
2418                        sx = "10000000000" + t;
2419                        break;
2420                    case 12:
2421                        sx = "1000000000" + t;
2422                        break;
2423                    case 13:
2424                        sx = "100000000" + t;
2425                        break;
2426                    case 14:
2427                        sx = "10000000" + t;
2428                        break;
2429                    case 15:
2430                        sx = "1000000" + t;
2431                        break;
2432                    case 16:
2433                        sx = "100000" + t;
2434                        break;
2435                    case 17:
2436                        sx = "10000" + t;
2437                        break;
2438                    case 18:
2439                        sx = "1000" + t;
2440                        break;
2441                    case 19:
2442                        sx = "100" + t;
2443                        break;
2444                    case 20:
2445                        sx = "10" + t;
2446                        break;
2447                    case 21:
2448                        sx = "1" + t;
2449                        break;
2450                    default:
2451                        // noop
2452                }
2453            } else {
2454                sx = Long.toString(x, 8);
2455            }
2456            return printOFormat(sx);
2457        }
2458
2459        /**
2460         * Format method for the o conversion character and
2461         * short argument.
2462         *
2463         * For o format, the flag character '-', means that
2464         * the output should be left justified within the
2465         * field.  The default is to pad with blanks on the
2466         * left.  The '#' flag character means that the
2467         * output begins with a leading 0 and the precision
2468         * is increased by 1.
2469         *
2470         * The field width is treated as the minimum number
2471         * of characters to be printed.  The default is to
2472         * add no padding.  Padding is with blanks by
2473         * default.
2474         *
2475         * The precision, if set, is the minimum number of
2476         * digits to appear.  Padding is with leading 0s.
2477         * @param x the short to format.
2478         * @return the formatted String.
2479         */
2480        private String printOFormat(short x) {
2481
2482            String sx = null;
2483            if (x == Short.MIN_VALUE) {
2484                sx = "100000";
2485            } else if (x < 0) {
2486                String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8);
2487                switch (t.length()) {
2488                    case 1:
2489                        sx = "10000" + t;
2490                        break;
2491                    case 2:
2492                        sx = "1000" + t;
2493                        break;
2494                    case 3:
2495                        sx = "100" + t;
2496                        break;
2497                    case 4:
2498                        sx = "10" + t;
2499                        break;
2500                    case 5:
2501                        sx = "1" + t;
2502                        break;
2503                    default:
2504                        // noop
2505                }
2506            } else {
2507                sx = Integer.toString(x, 8);
2508            }
2509            return printOFormat(sx);
2510        }
2511
2512        /**
2513         * Utility method for formatting using the o
2514         * conversion character.
2515         * @param sx the String to format, the result of
2516         *     converting a short, int, or long to a
2517         *     String.
2518         * @return the formatted String.
2519         */
2520        private String printOFormat(String sx) {
2521
2522            int nLeadingZeros = 0;
2523            int nBlanks = 0;
2524            if (sx.equals("0") && m_precisionSet && (m_precision == 0)) {
2525                sx = "";
2526            }
2527            if (m_precisionSet) {
2528                nLeadingZeros = m_precision - sx.length();
2529            }
2530            if (m_alternateForm) {
2531                nLeadingZeros++;
2532            }
2533            if (nLeadingZeros < 0) {
2534                nLeadingZeros = 0;
2535            }
2536            if (m_fieldWidthSet) {
2537                nBlanks = m_fieldWidth - nLeadingZeros - sx.length();
2538            }
2539            if (nBlanks < 0) {
2540                nBlanks = 0;
2541            }
2542            int n = nLeadingZeros + sx.length() + nBlanks;
2543            char[] ca = new char[n];
2544            int i;
2545            if (m_leftJustify) {
2546                for (i = 0; i < nLeadingZeros; i++) {
2547                    ca[i] = '0';
2548                }
2549                char[] csx = sx.toCharArray();
2550                for (int j = 0; j < csx.length; j++, i++) {
2551                    ca[i] = csx[j];
2552                }
2553                for (int j = 0; j < nBlanks; j++, i++) {
2554                    ca[i] = ' ';
2555                }
2556            } else {
2557                if (m_leadingZeros) {
2558                    for (i = 0; i < nBlanks; i++) {
2559                        ca[i] = '0';
2560                    }
2561                } else {
2562                    for (i = 0; i < nBlanks; i++) {
2563                        ca[i] = ' ';
2564                    }
2565                }
2566                for (int j = 0; j < nLeadingZeros; j++, i++) {
2567                    ca[i] = '0';
2568                }
2569                char[] csx = sx.toCharArray();
2570                for (int j = 0; j < csx.length; j++, i++) {
2571                    ca[i] = csx[j];
2572                }
2573            }
2574            return new String(ca);
2575        }
2576
2577        /**
2578         * Format method for the s conversion character and
2579         * String argument.
2580         *
2581         * The only flag character that affects s format is
2582         * the '-', meaning that the output should be left
2583         * justified within the field.  The default is to
2584         * pad with blanks on the left.
2585         *
2586         * The field width is treated as the minimum number
2587         * of characters to be printed.  The default is the
2588         * smaller of the number of characters in the the
2589         * input and the precision.  Padding is with blanks
2590         * by default.
2591         *
2592         * The precision, if set, specifies the maximum
2593         * number of characters to be printed from the
2594         * string.  A null digit string is treated
2595         * as a 0.  The default is not to set a maximum
2596         * number of characters to be printed.
2597         * @param x the String to format.
2598         * @return the formatted String.
2599         */
2600        private String printSFormat(String x) {
2601
2602            int nPrint = x.length();
2603            int width = m_fieldWidth;
2604            if (m_precisionSet && (nPrint > m_precision)) {
2605                nPrint = m_precision;
2606            }
2607            if (!m_fieldWidthSet) {
2608                width = nPrint;
2609            }
2610            int n = 0;
2611            if (width > nPrint) {
2612                n += width - nPrint;
2613            }
2614            if (nPrint >= x.length()) {
2615                n += x.length();
2616            } else {
2617                n += nPrint;
2618            }
2619            char[] ca = new char[n];
2620            int i = 0;
2621            if (m_leftJustify) {
2622                if (nPrint >= x.length()) {
2623                    char[] csx = x.toCharArray();
2624                    for (i = 0; i < x.length(); i++) {
2625                        ca[i] = csx[i];
2626                    }
2627                } else {
2628                    char[] csx = x.substring(0, nPrint).toCharArray();
2629                    for (i = 0; i < nPrint; i++) {
2630                        ca[i] = csx[i];
2631                    }
2632                }
2633                for (int j = 0; j < (width - nPrint); j++, i++) {
2634                    ca[i] = ' ';
2635                }
2636            } else {
2637                for (i = 0; i < (width - nPrint); i++) {
2638                    ca[i] = ' ';
2639                }
2640                if (nPrint >= x.length()) {
2641                    char[] csx = x.toCharArray();
2642                    for (int j = 0; j < x.length(); i++, j++) {
2643                        ca[i] = csx[j];
2644                    }
2645                } else {
2646                    char[] csx = x.substring(0, nPrint).toCharArray();
2647                    for (int j = 0; j < nPrint; i++, j++) {
2648                        ca[i] = csx[j];
2649                    }
2650                }
2651            }
2652            return new String(ca);
2653        }
2654
2655        /**
2656         * Format method for the x conversion character and
2657         * int argument.
2658         *
2659         * For x format, the flag character '-', means that
2660         * the output should be left justified within the
2661         * field.  The default is to pad with blanks on the
2662         * left.  The '#' flag character means to lead with
2663         * '0x'.
2664         *
2665         * The field width is treated as the minimum number
2666         * of characters to be printed.  The default is to
2667         * add no padding.  Padding is with blanks by
2668         * default.
2669         *
2670         * The precision, if set, is the minimum number of
2671         * digits to appear.  Padding is with leading 0s.
2672         * @param x the int to format.
2673         * @return the formatted String.
2674         */
2675        private String printXFormat(int x) {
2676
2677            String sx = null;
2678            if (x == Integer.MIN_VALUE) {
2679                sx = "80000000";
2680            } else if (x < 0) {
2681                String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16);
2682                switch (t.length()) {
2683                    case 1:
2684                        sx = "8000000" + t;
2685                        break;
2686                    case 2:
2687                        sx = "800000" + t;
2688                        break;
2689                    case 3:
2690                        sx = "80000" + t;
2691                        break;
2692                    case 4:
2693                        sx = "8000" + t;
2694                        break;
2695                    case 5:
2696                        sx = "800" + t;
2697                        break;
2698                    case 6:
2699                        sx = "80" + t;
2700                        break;
2701                    case 7:
2702                        sx = "8" + t;
2703                        break;
2704                    case 8:
2705                        switch (t.charAt(0)) {
2706                            case '1':
2707                                sx = "9" + t.substring(1, 8);
2708                                break;
2709                            case '2':
2710                                sx = "a" + t.substring(1, 8);
2711                                break;
2712                            case '3':
2713                                sx = "b" + t.substring(1, 8);
2714                                break;
2715                            case '4':
2716                                sx = "c" + t.substring(1, 8);
2717                                break;
2718                            case '5':
2719                                sx = "d" + t.substring(1, 8);
2720                                break;
2721                            case '6':
2722                                sx = "e" + t.substring(1, 8);
2723                                break;
2724                            case '7':
2725                                sx = "f" + t.substring(1, 8);
2726                                break;
2727                            default:
2728                                // noop
2729                        }
2730                        break;
2731                    default:
2732                        // noop
2733                }
2734            } else {
2735                sx = Integer.toString(x, 16);
2736            }
2737            return printXFormat(sx);
2738        }
2739
2740        /**
2741         * Format method for the x conversion character and
2742         * long argument.
2743         *
2744         * For x format, the flag character '-', means that
2745         * the output should be left justified within the
2746         * field.  The default is to pad with blanks on the
2747         * left.  The '#' flag character means to lead with
2748         * '0x'.
2749         *
2750         * The field width is treated as the minimum number
2751         * of characters to be printed.  The default is to
2752         * add no padding.  Padding is with blanks by
2753         * default.
2754         *
2755         * The precision, if set, is the minimum number of
2756         * digits to appear.  Padding is with leading 0s.
2757         * @param x the long to format.
2758         * @return the formatted String.
2759         */
2760        private String printXFormat(long x) {
2761
2762            String sx = null;
2763            if (x == Long.MIN_VALUE) {
2764                sx = "8000000000000000";
2765            } else if (x < 0) {
2766                String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16);
2767                switch (t.length()) {
2768                    case 1:
2769                        sx = "800000000000000" + t;
2770                        break;
2771                    case 2:
2772                        sx = "80000000000000" + t;
2773                        break;
2774                    case 3:
2775                        sx = "8000000000000" + t;
2776                        break;
2777                    case 4:
2778                        sx = "800000000000" + t;
2779                        break;
2780                    case 5:
2781                        sx = "80000000000" + t;
2782                        break;
2783                    case 6:
2784                        sx = "8000000000" + t;
2785                        break;
2786                    case 7:
2787                        sx = "800000000" + t;
2788                        break;
2789                    case 8:
2790                        sx = "80000000" + t;
2791                        break;
2792                    case 9:
2793                        sx = "8000000" + t;
2794                        break;
2795                    case 10:
2796                        sx = "800000" + t;
2797                        break;
2798                    case 11:
2799                        sx = "80000" + t;
2800                        break;
2801                    case 12:
2802                        sx = "8000" + t;
2803                        break;
2804                    case 13:
2805                        sx = "800" + t;
2806                        break;
2807                    case 14:
2808                        sx = "80" + t;
2809                        break;
2810                    case 15:
2811                        sx = "8" + t;
2812                        break;
2813                    case 16:
2814                        switch (t.charAt(0)) {
2815                            case '1':
2816                                sx = "9" + t.substring(1, 16);
2817                                break;
2818                            case '2':
2819                                sx = "a" + t.substring(1, 16);
2820                                break;
2821                            case '3':
2822                                sx = "b" + t.substring(1, 16);
2823                                break;
2824                            case '4':
2825                                sx = "c" + t.substring(1, 16);
2826                                break;
2827                            case '5':
2828                                sx = "d" + t.substring(1, 16);
2829                                break;
2830                            case '6':
2831                                sx = "e" + t.substring(1, 16);
2832                                break;
2833                            case '7':
2834                                sx = "f" + t.substring(1, 16);
2835                                break;
2836                            default:
2837                                // noop
2838                        }
2839                        break;
2840                    default:
2841                        // noop
2842                }
2843            } else {
2844                sx = Long.toString(x, 16);
2845            }
2846            return printXFormat(sx);
2847        }
2848
2849        /**
2850         * Format method for the x conversion character and
2851         * short argument.
2852         *
2853         * For x format, the flag character '-', means that
2854         * the output should be left justified within the
2855         * field.  The default is to pad with blanks on the
2856         * left.  The '#' flag character means to lead with
2857         * '0x'.
2858         *
2859         * The field width is treated as the minimum number
2860         * of characters to be printed.  The default is to
2861         * add no padding.  Padding is with blanks by
2862         * default.
2863         *
2864         * The precision, if set, is the minimum number of
2865         * digits to appear.  Padding is with leading 0s.
2866         * @param x the short to format.
2867         * @return the formatted String.
2868         */
2869        private String printXFormat(short x) {
2870
2871            String sx = null;
2872            if (x == Short.MIN_VALUE) {
2873                sx = "8000";
2874            } else if (x < 0) {
2875                String t;
2876                if (x == Short.MIN_VALUE) {
2877                    t = "0";
2878                } else {
2879                    t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16);
2880                    if ((t.charAt(0) == 'F') || (t.charAt(0) == 'f')) {
2881                        t = t.substring(16, 32);
2882                    }
2883                }
2884                switch (t.length()) {
2885                    case 1:
2886                        sx = "800" + t;
2887                        break;
2888                    case 2:
2889                        sx = "80" + t;
2890                        break;
2891                    case 3:
2892                        sx = "8" + t;
2893                        break;
2894                    case 4:
2895                        switch (t.charAt(0)) {
2896                            case '1':
2897                                sx = "9" + t.substring(1, 4);
2898                                break;
2899                            case '2':
2900                                sx = "a" + t.substring(1, 4);
2901                                break;
2902                            case '3':
2903                                sx = "b" + t.substring(1, 4);
2904                                break;
2905                            case '4':
2906                                sx = "c" + t.substring(1, 4);
2907                                break;
2908                            case '5':
2909                                sx = "d" + t.substring(1, 4);
2910                                break;
2911                            case '6':
2912                                sx = "e" + t.substring(1, 4);
2913                                break;
2914                            case '7':
2915                                sx = "f" + t.substring(1, 4);
2916                                break;
2917                            default:
2918                                // noop
2919                        }
2920                        break;
2921                    default:
2922                        // noop
2923                }
2924            } else {
2925                sx = Integer.toString(x, 16);
2926            }
2927            return printXFormat(sx);
2928        }
2929
2930        /**
2931         * Utility method for formatting using the x
2932         * conversion character.
2933         * @param sx the String to format, the result of
2934         *     converting a short, int, or long to a
2935         *     String.
2936         * @return the formatted String.
2937         */
2938        private String printXFormat(String sx) {
2939
2940            int nLeadingZeros = 0;
2941            int nBlanks = 0;
2942            if (sx.equals("0") && m_precisionSet && (m_precision == 0)) {
2943                sx = "";
2944            }
2945            if (m_precisionSet) {
2946                nLeadingZeros = m_precision - sx.length();
2947            }
2948            if (nLeadingZeros < 0) {
2949                nLeadingZeros = 0;
2950            }
2951            if (m_fieldWidthSet) {
2952                nBlanks = m_fieldWidth - nLeadingZeros - sx.length();
2953                if (m_alternateForm) {
2954                    nBlanks = nBlanks - 2;
2955                }
2956            }
2957            if (nBlanks < 0) {
2958                nBlanks = 0;
2959            }
2960            int n = 0;
2961            if (m_alternateForm) {
2962                n += 2;
2963            }
2964            n += nLeadingZeros;
2965            n += sx.length();
2966            n += nBlanks;
2967            char[] ca = new char[n];
2968            int i = 0;
2969            if (m_leftJustify) {
2970                if (m_alternateForm) {
2971                    ca[i++] = '0';
2972                    ca[i++] = 'x';
2973                }
2974                for (int j = 0; j < nLeadingZeros; j++, i++) {
2975                    ca[i] = '0';
2976                }
2977                char[] csx = sx.toCharArray();
2978                for (int j = 0; j < csx.length; j++, i++) {
2979                    ca[i] = csx[j];
2980                }
2981                for (int j = 0; j < nBlanks; j++, i++) {
2982                    ca[i] = ' ';
2983                }
2984            } else {
2985                if (!m_leadingZeros) {
2986                    for (int j = 0; j < nBlanks; j++, i++) {
2987                        ca[i] = ' ';
2988                    }
2989                }
2990                if (m_alternateForm) {
2991                    ca[i++] = '0';
2992                    ca[i++] = 'x';
2993                }
2994                if (m_leadingZeros) {
2995                    for (int j = 0; j < nBlanks; j++, i++) {
2996                        ca[i] = '0';
2997                    }
2998                }
2999                for (int j = 0; j < nLeadingZeros; j++, i++) {
3000                    ca[i] = '0';
3001                }
3002                char[] csx = sx.toCharArray();
3003                for (int j = 0; j < csx.length; j++, i++) {
3004                    ca[i] = csx[j];
3005                }
3006            }
3007            String caReturn = new String(ca);
3008            if (m_conversionCharacter == 'X') {
3009                caReturn = caReturn.toUpperCase();
3010            }
3011            return caReturn;
3012        }
3013
3014        /**
3015         * Store the digits <code>n</code> in %n$ forms.
3016         */
3017        private void setArgPosition() {
3018
3019            int xPos;
3020            for (xPos = m_pos; xPos < m_fmt.length(); xPos++) {
3021                if (!Character.isDigit(m_fmt.charAt(xPos))) {
3022                    break;
3023                }
3024            }
3025            if ((xPos > m_pos) && (xPos < m_fmt.length())) {
3026                if (m_fmt.charAt(xPos) == '$') {
3027                    m_positionalSpecification = true;
3028                    m_argumentPosition = Integer.parseInt(m_fmt.substring(m_pos, xPos));
3029                    m_pos = xPos + 1;
3030                }
3031            }
3032        }
3033
3034        /**
3035         * Check for a conversion character.  If it is
3036         * there, store it.
3037         * @return <code>true</code> if the conversion
3038         *     character is there, and
3039         *     <code>false</code> otherwise.
3040         */
3041        private boolean setConversionCharacter() {
3042
3043            /* idfgGoxXeEcs */
3044            boolean ret = false;
3045            m_conversionCharacter = '\0';
3046            if (m_pos < m_fmt.length()) {
3047                char c = m_fmt.charAt(m_pos);
3048                if ((c == 'i')
3049                    || (c == 'd')
3050                    || (c == 'f')
3051                    || (c == 'g')
3052                    || (c == 'G')
3053                    || (c == 'o')
3054                    || (c == 'x')
3055                    || (c == 'X')
3056                    || (c == 'e')
3057                    || (c == 'E')
3058                    || (c == 'c')
3059                    || (c == 's')
3060                    || (c == '%')) {
3061                    m_conversionCharacter = c;
3062                    m_pos++;
3063                    ret = true;
3064                }
3065            }
3066            return ret;
3067        }
3068
3069        /**
3070         * Set the field width.
3071         */
3072        private void setFieldWidth() {
3073
3074            int firstPos = m_pos;
3075            m_fieldWidth = 0;
3076            m_fieldWidthSet = false;
3077            if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '*')) {
3078                m_pos++;
3079                if (!setFieldWidthArgPosition()) {
3080                    m_variableFieldWidth = true;
3081                    m_fieldWidthSet = true;
3082                }
3083            } else {
3084                while (m_pos < m_fmt.length()) {
3085                    char c = m_fmt.charAt(m_pos);
3086                    if (Character.isDigit(c)) {
3087                        m_pos++;
3088                    } else {
3089                        break;
3090                    }
3091                }
3092                if ((firstPos < m_pos) && (firstPos < m_fmt.length())) {
3093                    String sz = m_fmt.substring(firstPos, m_pos);
3094                    m_fieldWidth = Integer.parseInt(sz);
3095                    m_fieldWidthSet = true;
3096                }
3097            }
3098        }
3099
3100        /**
3101         * Store the digits <code>n</code> in *n$ forms.
3102         *
3103         * @return the result
3104         */
3105        private boolean setFieldWidthArgPosition() {
3106
3107            boolean ret = false;
3108            int xPos;
3109            for (xPos = m_pos; xPos < m_fmt.length(); xPos++) {
3110                if (!Character.isDigit(m_fmt.charAt(xPos))) {
3111                    break;
3112                }
3113            }
3114            if ((xPos > m_pos) && (xPos < m_fmt.length())) {
3115                if (m_fmt.charAt(xPos) == '$') {
3116                    m_positionalFieldWidth = true;
3117                    m_argumentPositionForFieldWidth = Integer.parseInt(m_fmt.substring(m_pos, xPos));
3118                    m_pos = xPos + 1;
3119                    ret = true;
3120                }
3121            }
3122            return ret;
3123        }
3124
3125        /**
3126         * Set flag characters, one of '-+#0 or a space.
3127         */
3128        private void setFlagCharacters() {
3129
3130            /* '-+ #0 */
3131            m_thousands = false;
3132            m_leftJustify = false;
3133            m_leadingSign = false;
3134            m_leadingSpace = false;
3135            m_alternateForm = false;
3136            m_leadingZeros = false;
3137            for (; m_pos < m_fmt.length(); m_pos++) {
3138                char c = m_fmt.charAt(m_pos);
3139                if (c == '\'') {
3140                    m_thousands = true;
3141                } else if (c == '-') {
3142                    m_leftJustify = true;
3143                    m_leadingZeros = false;
3144                } else if (c == '+') {
3145                    m_leadingSign = true;
3146                    m_leadingSpace = false;
3147                } else if (c == ' ') {
3148                    if (!m_leadingSign) {
3149                        m_leadingSpace = true;
3150                    }
3151                } else if (c == '#') {
3152                    m_alternateForm = true;
3153                } else if (c == '0') {
3154                    if (!m_leftJustify) {
3155                        m_leadingZeros = true;
3156                    }
3157                } else {
3158                    break;
3159                }
3160            }
3161        }
3162
3163        /**
3164         * Check for an h, l, or L in a format.  An L is
3165         * used to control the minimum number of digits
3166         * in an exponent when using floating point
3167         * formats.  An l or h is used to control
3168         * conversion of the input to a long or short,
3169         * respectively, before formatting.  If any of
3170         * these is present, store them.
3171         */
3172        private void setOptionalHL() {
3173
3174            m_optionalh = false;
3175            m_optionall = false;
3176            m_optionalL = false;
3177            if (m_pos < m_fmt.length()) {
3178                char c = m_fmt.charAt(m_pos);
3179                if (c == 'h') {
3180                    m_optionalh = true;
3181                    m_pos++;
3182                } else if (c == 'l') {
3183                    m_optionall = true;
3184                    m_pos++;
3185                } else if (c == 'L') {
3186                    m_optionalL = true;
3187                    m_pos++;
3188                }
3189            }
3190        }
3191
3192        /**
3193         * Set the precision.
3194         */
3195        private void setPrecision() {
3196
3197            int firstPos = m_pos;
3198            m_precisionSet = false;
3199            if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '.')) {
3200                m_pos++;
3201                if ((m_pos < m_fmt.length()) && (m_fmt.charAt(m_pos) == '*')) {
3202                    m_pos++;
3203                    if (!setPrecisionArgPosition()) {
3204                        m_variablePrecision = true;
3205                        m_precisionSet = true;
3206                    }
3207                    return;
3208                } else {
3209                    while (m_pos < m_fmt.length()) {
3210                        char c = m_fmt.charAt(m_pos);
3211                        if (Character.isDigit(c)) {
3212                            m_pos++;
3213                        } else {
3214                            break;
3215                        }
3216                    }
3217                    if (m_pos > (firstPos + 1)) {
3218                        String sz = m_fmt.substring(firstPos + 1, m_pos);
3219                        m_precision = Integer.parseInt(sz);
3220                        m_precisionSet = true;
3221                    }
3222                }
3223            }
3224        }
3225
3226        /**
3227         * Store the digits <code>n</code> in *n$ forms.
3228         *
3229         * @return the result
3230         */
3231        private boolean setPrecisionArgPosition() {
3232
3233            boolean ret = false;
3234            int xPos;
3235            for (xPos = m_pos; xPos < m_fmt.length(); xPos++) {
3236                if (!Character.isDigit(m_fmt.charAt(xPos))) {
3237                    break;
3238                }
3239            }
3240            if ((xPos > m_pos) && (xPos < m_fmt.length())) {
3241                if (m_fmt.charAt(xPos) == '$') {
3242                    m_positionalPrecision = true;
3243                    m_argumentPositionForPrecision = Integer.parseInt(m_fmt.substring(m_pos, xPos));
3244                    m_pos = xPos + 1;
3245                    ret = true;
3246                }
3247            }
3248            return ret;
3249        }
3250
3251        /**
3252         * Start the symbolic carry process.  The process
3253         * is not quite finished because the symbolic
3254         * carry may change the length of the string and
3255         * change the exponent (in e format).
3256         * @param cLast index of the last digit changed
3257         *     by the round
3258         * @param cFirst index of the first digit allowed
3259         *     to be changed by this phase of the round
3260         * @param ca the ca parameter
3261         * @return <code>true</code> if the carry forces
3262         *     a round that will change the print still
3263         *     more
3264         */
3265        private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) {
3266
3267            boolean carry = true;
3268            for (int i = cLast; carry && (i >= cFirst); i--) {
3269                carry = false;
3270                switch (ca[i]) {
3271                    case '0':
3272                        ca[i] = '1';
3273                        break;
3274                    case '1':
3275                        ca[i] = '2';
3276                        break;
3277                    case '2':
3278                        ca[i] = '3';
3279                        break;
3280                    case '3':
3281                        ca[i] = '4';
3282                        break;
3283                    case '4':
3284                        ca[i] = '5';
3285                        break;
3286                    case '5':
3287                        ca[i] = '6';
3288                        break;
3289                    case '6':
3290                        ca[i] = '7';
3291                        break;
3292                    case '7':
3293                        ca[i] = '8';
3294                        break;
3295                    case '8':
3296                        ca[i] = '9';
3297                        break;
3298                    case '9':
3299                        ca[i] = '0';
3300                        carry = true;
3301                        break;
3302                    default:
3303                        // noop
3304                }
3305            }
3306            return carry;
3307        }
3308    }
3309
3310    /** Character position. Used by the constructor. */
3311    DecimalFormatSymbols m_dfs;
3312
3313    /** Character position. Used by the constructor. */
3314    private int m_cPos;
3315
3316    /** Vector of control strings and format literals. */
3317    private Vector<ConversionSpecification> m_vFmt = new Vector<ConversionSpecification>();
3318
3319    /**
3320     * Constructs an array of control specifications
3321     * possibly preceded, separated, or followed by
3322     * ordinary strings.  Control strings begin with
3323     * unpaired percent signs.  A pair of successive
3324     * percent signs designates a single percent sign in
3325     * the format.
3326     * @param locale the locale
3327     * @param fmtArg  Control string.
3328     * @exception CmsIllegalArgumentException if the control
3329     * string is null, zero length, or otherwise
3330     * malformed.
3331     */
3332    public PrintfFormat(Locale locale, String fmtArg)
3333    throws CmsIllegalArgumentException {
3334
3335        m_dfs = new DecimalFormatSymbols(locale);
3336        int ePos = 0;
3337        ConversionSpecification sFmt = null;
3338        String unCS = nonControl(fmtArg, 0);
3339        if (unCS != null) {
3340            sFmt = new ConversionSpecification();
3341            sFmt.setLiteral(unCS);
3342            m_vFmt.addElement(sFmt);
3343        }
3344        while ((m_cPos != -1) && (m_cPos < fmtArg.length())) {
3345            for (ePos = m_cPos + 1; ePos < fmtArg.length(); ePos++) {
3346                char c = 0;
3347                c = fmtArg.charAt(ePos);
3348                if (c == 'i') {
3349                    break;
3350                }
3351                if (c == 'd') {
3352                    break;
3353                }
3354                if (c == 'f') {
3355                    break;
3356                }
3357                if (c == 'g') {
3358                    break;
3359                }
3360                if (c == 'G') {
3361                    break;
3362                }
3363                if (c == 'o') {
3364                    break;
3365                }
3366                if (c == 'x') {
3367                    break;
3368                }
3369                if (c == 'X') {
3370                    break;
3371                }
3372                if (c == 'e') {
3373                    break;
3374                }
3375                if (c == 'E') {
3376                    break;
3377                }
3378                if (c == 'c') {
3379                    break;
3380                }
3381                if (c == 's') {
3382                    break;
3383                }
3384                if (c == '%') {
3385                    break;
3386                }
3387            }
3388            ePos = Math.min(ePos + 1, fmtArg.length());
3389            sFmt = new ConversionSpecification(fmtArg.substring(m_cPos, ePos));
3390            m_vFmt.addElement(sFmt);
3391            unCS = nonControl(fmtArg, ePos);
3392            if (unCS != null) {
3393                sFmt = new ConversionSpecification();
3394                sFmt.setLiteral(unCS);
3395                m_vFmt.addElement(sFmt);
3396            }
3397        }
3398    }
3399
3400    /**
3401     * Constructs an array of control specifications
3402     * possibly preceded, separated, or followed by
3403     * ordinary strings.  Control strings begin with
3404     * unpaired percent signs.  A pair of successive
3405     * percent signs designates a single percent sign in
3406     * the format.
3407     * @param fmtArg  Control string.
3408     * @exception IllegalArgumentException if the control
3409     * string is null, zero length, or otherwise
3410     * malformed.
3411     */
3412    public PrintfFormat(String fmtArg)
3413    throws IllegalArgumentException {
3414
3415        this(Locale.getDefault(), fmtArg);
3416    }
3417
3418    /**
3419     * Format nothing.  Just use the control string.
3420     * @return  the formatted String.
3421     */
3422    public String sprintf() {
3423
3424        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3425        ConversionSpecification cs = null;
3426        char c = 0;
3427        StringBuffer sb = new StringBuffer();
3428        while (e.hasMoreElements()) {
3429            cs = e.nextElement();
3430            c = cs.getConversionCharacter();
3431            if (c == '\0') {
3432                sb.append(cs.getLiteral());
3433            } else if (c == '%') {
3434                sb.append("%");
3435            }
3436        }
3437        return sb.toString();
3438    }
3439
3440    /**
3441     * Format a double.
3442     * @param x The double to format.
3443     * @return  The formatted String.
3444     * @exception CmsIllegalArgumentException if the
3445     *     conversion character is c, C, s, S,
3446     *     d, d, x, X, or o.
3447     */
3448    public String sprintf(double x) throws CmsIllegalArgumentException {
3449
3450        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3451        ConversionSpecification cs = null;
3452        char c = 0;
3453        StringBuffer sb = new StringBuffer();
3454        while (e.hasMoreElements()) {
3455            cs = e.nextElement();
3456            c = cs.getConversionCharacter();
3457            if (c == '\0') {
3458                sb.append(cs.getLiteral());
3459            } else if (c == '%') {
3460                sb.append("%");
3461            } else {
3462                sb.append(cs.internalsprintf(x));
3463            }
3464        }
3465        return sb.toString();
3466    }
3467
3468    /**
3469     * Format an int.
3470     * @param x The int to format.
3471     * @return  The formatted String.
3472     * @exception CmsIllegalArgumentException if the
3473     *     conversion character is f, e, E, g, G, s,
3474     *     or S.
3475     */
3476    public String sprintf(int x) throws CmsIllegalArgumentException {
3477
3478        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3479        ConversionSpecification cs = null;
3480        char c = 0;
3481        StringBuffer sb = new StringBuffer();
3482        while (e.hasMoreElements()) {
3483            cs = e.nextElement();
3484            c = cs.getConversionCharacter();
3485            if (c == '\0') {
3486                sb.append(cs.getLiteral());
3487            } else if (c == '%') {
3488                sb.append("%");
3489            } else {
3490                sb.append(cs.internalsprintf(x));
3491            }
3492        }
3493        return sb.toString();
3494    }
3495
3496    /**
3497     * Format an long.
3498     * @param x The long to format.
3499     * @return  The formatted String.
3500     * @exception CmsIllegalArgumentException if the
3501     *     conversion character is f, e, E, g, G, s,
3502     *     or S.
3503     */
3504    public String sprintf(long x) throws CmsIllegalArgumentException {
3505
3506        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3507        ConversionSpecification cs = null;
3508        char c = 0;
3509        StringBuffer sb = new StringBuffer();
3510        while (e.hasMoreElements()) {
3511            cs = e.nextElement();
3512            c = cs.getConversionCharacter();
3513            if (c == '\0') {
3514                sb.append(cs.getLiteral());
3515            } else if (c == '%') {
3516                sb.append("%");
3517            } else {
3518                sb.append(cs.internalsprintf(x));
3519            }
3520        }
3521        return sb.toString();
3522    }
3523
3524    /**
3525     * Format an Object.  Convert wrapper types to
3526     * their primitive equivalents and call the
3527     * appropriate internal formatting method. Convert
3528     * Strings using an internal formatting method for
3529     * Strings. Otherwise use the default formatter
3530     * (use toString).
3531     * @param x the Object to format.
3532     * @return  the formatted String.
3533     * @exception CmsIllegalArgumentException if the
3534     *    conversion character is inappropriate for
3535     *    formatting an unwrapped value.
3536     */
3537    public String sprintf(Object x) throws CmsIllegalArgumentException {
3538
3539        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3540        ConversionSpecification cs = null;
3541        char c = 0;
3542        StringBuffer sb = new StringBuffer();
3543        while (e.hasMoreElements()) {
3544            cs = e.nextElement();
3545            c = cs.getConversionCharacter();
3546            if (c == '\0') {
3547                sb.append(cs.getLiteral());
3548            } else if (c == '%') {
3549                sb.append("%");
3550            } else {
3551                if (x instanceof Byte) {
3552                    sb.append(cs.internalsprintf(((Byte)x).byteValue()));
3553                } else if (x instanceof Short) {
3554                    sb.append(cs.internalsprintf(((Short)x).shortValue()));
3555                } else if (x instanceof Integer) {
3556                    sb.append(cs.internalsprintf(((Integer)x).intValue()));
3557                } else if (x instanceof Long) {
3558                    sb.append(cs.internalsprintf(((Long)x).longValue()));
3559                } else if (x instanceof Float) {
3560                    sb.append(cs.internalsprintf(((Float)x).floatValue()));
3561                } else if (x instanceof Double) {
3562                    sb.append(cs.internalsprintf(((Double)x).doubleValue()));
3563                } else if (x instanceof Character) {
3564                    sb.append(cs.internalsprintf(((Character)x).charValue()));
3565                } else if (x instanceof String) {
3566                    sb.append(cs.internalsprintf((String)x));
3567                } else {
3568                    sb.append(cs.internalsprintf(x));
3569                }
3570            }
3571        }
3572        return sb.toString();
3573    }
3574
3575    /**
3576     * Format an array of objects.  Byte, Short,
3577     * Integer, Long, Float, Double, and Character
3578     * arguments are treated as wrappers for primitive
3579     * types.
3580     * @param o The array of objects to format.
3581     * @return  The formatted String.
3582     */
3583    public String sprintf(Object[] o) {
3584
3585        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3586        ConversionSpecification cs = null;
3587        char c = 0;
3588        int i = 0;
3589        StringBuffer sb = new StringBuffer();
3590        while (e.hasMoreElements()) {
3591            cs = 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 (cs.isPositionalSpecification()) {
3599                    i = cs.getArgumentPosition() - 1;
3600                    if (cs.isPositionalFieldWidth()) {
3601                        int ifw = cs.getArgumentPositionForFieldWidth() - 1;
3602                        cs.setFieldWidthWithArg(((Integer)o[ifw]).intValue());
3603                    }
3604                    if (cs.isPositionalPrecision()) {
3605                        int ipr = cs.getArgumentPositionForPrecision() - 1;
3606                        cs.setPrecisionWithArg(((Integer)o[ipr]).intValue());
3607                    }
3608                } else {
3609                    if (cs.isVariableFieldWidth()) {
3610                        cs.setFieldWidthWithArg(((Integer)o[i]).intValue());
3611                        i++;
3612                    }
3613                    if (cs.isVariablePrecision()) {
3614                        cs.setPrecisionWithArg(((Integer)o[i]).intValue());
3615                        i++;
3616                    }
3617                }
3618                if (o[i] instanceof Byte) {
3619                    sb.append(cs.internalsprintf(((Byte)o[i]).byteValue()));
3620                } else if (o[i] instanceof Short) {
3621                    sb.append(cs.internalsprintf(((Short)o[i]).shortValue()));
3622                } else if (o[i] instanceof Integer) {
3623                    sb.append(cs.internalsprintf(((Integer)o[i]).intValue()));
3624                } else if (o[i] instanceof Long) {
3625                    sb.append(cs.internalsprintf(((Long)o[i]).longValue()));
3626                } else if (o[i] instanceof Float) {
3627                    sb.append(cs.internalsprintf(((Float)o[i]).floatValue()));
3628                } else if (o[i] instanceof Double) {
3629                    sb.append(cs.internalsprintf(((Double)o[i]).doubleValue()));
3630                } else if (o[i] instanceof Character) {
3631                    sb.append(cs.internalsprintf(((Character)o[i]).charValue()));
3632                } else if (o[i] instanceof String) {
3633                    sb.append(cs.internalsprintf((String)o[i]));
3634                } else {
3635                    sb.append(cs.internalsprintf(o[i]));
3636                }
3637                if (!cs.isPositionalSpecification()) {
3638                    i++;
3639                }
3640            }
3641        }
3642        return sb.toString();
3643    }
3644
3645    /**
3646     * Format a String.
3647     * @param x The String to format.
3648     * @return  The formatted String.
3649     * @exception CmsIllegalArgumentException if the
3650     *   conversion character is neither s nor S.
3651     */
3652    public String sprintf(String x) throws CmsIllegalArgumentException {
3653
3654        Enumeration<ConversionSpecification> e = m_vFmt.elements();
3655        ConversionSpecification cs = null;
3656        char c = 0;
3657        StringBuffer sb = new StringBuffer();
3658        while (e.hasMoreElements()) {
3659            cs = e.nextElement();
3660            c = cs.getConversionCharacter();
3661            if (c == '\0') {
3662                sb.append(cs.getLiteral());
3663            } else if (c == '%') {
3664                sb.append("%");
3665            } else {
3666                sb.append(cs.internalsprintf(x));
3667            }
3668        }
3669        return sb.toString();
3670    }
3671
3672    /**
3673     * Return a substring starting at
3674     * <code>start</code> and ending at either the end
3675     * of the String <code>s</code>, the next unpaired
3676     * percent sign, or at the end of the String if the
3677     * last character is a percent sign.
3678     * @param s  Control string.
3679     * @param start Position in the string
3680     *     <code>s</code> to begin looking for the start
3681     *     of a control string.
3682     * @return the substring from the start position
3683     *     to the beginning of the control string.
3684     */
3685    private String nonControl(String s, int start) {
3686
3687        m_cPos = s.indexOf("%", start);
3688        if (m_cPos == -1) {
3689            m_cPos = s.length();
3690        }
3691        return s.substring(start, m_cPos);
3692    }
3693}