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