View Javadoc

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