Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/java/util/Formatter.java
+++ new/src/share/classes/java/util/Formatter.java
1 1 /*
2 2 * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package java.util;
27 27
28 28 import java.io.BufferedWriter;
29 29 import java.io.Closeable;
30 30 import java.io.IOException;
31 31 import java.io.File;
32 32 import java.io.FileOutputStream;
33 33 import java.io.FileNotFoundException;
34 34 import java.io.Flushable;
35 35 import java.io.OutputStream;
36 36 import java.io.OutputStreamWriter;
37 37 import java.io.PrintStream;
38 38 import java.io.UnsupportedEncodingException;
39 39 import java.math.BigDecimal;
40 40 import java.math.BigInteger;
41 41 import java.math.MathContext;
42 42 import java.math.RoundingMode;
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
43 43 import java.nio.charset.Charset;
44 44 import java.text.DateFormatSymbols;
45 45 import java.text.DecimalFormat;
46 46 import java.text.DecimalFormatSymbols;
47 47 import java.text.NumberFormat;
48 48 import java.util.Calendar;
49 49 import java.util.Date;
50 50 import java.util.Locale;
51 51 import java.util.regex.Matcher;
52 52 import java.util.regex.Pattern;
53 +import java.nio.charset.Charset;
54 +import java.nio.charset.IllegalCharsetNameException;
53 55
54 56 import sun.misc.FpUtils;
55 57 import sun.misc.DoubleConsts;
56 58 import sun.misc.FormattedFloatingDecimal;
57 59
58 60 /**
59 61 * An interpreter for printf-style format strings. This class provides support
60 62 * for layout justification and alignment, common formats for numeric, string,
61 63 * and date/time data, and locale-specific output. Common Java types such as
62 64 * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
63 65 * are supported. Limited formatting customization for arbitrary user types is
64 66 * provided through the {@link Formattable} interface.
65 67 *
66 68 * <p> Formatters are not necessarily safe for multithreaded access. Thread
67 69 * safety is optional and is the responsibility of users of methods in this
68 70 * class.
69 71 *
70 72 * <p> Formatted printing for the Java language is heavily inspired by C's
71 73 * {@code printf}. Although the format strings are similar to C, some
72 74 * customizations have been made to accommodate the Java language and exploit
73 75 * some of its features. Also, Java formatting is more strict than C's; for
74 76 * example, if a conversion is incompatible with a flag, an exception will be
75 77 * thrown. In C inapplicable flags are silently ignored. The format strings
76 78 * are thus intended to be recognizable to C programmers but not necessarily
77 79 * completely compatible with those in C.
78 80 *
79 81 * <p> Examples of expected usage:
80 82 *
81 83 * <blockquote><pre>
82 84 * StringBuilder sb = new StringBuilder();
83 85 * // Send all output to the Appendable object sb
84 86 * Formatter formatter = new Formatter(sb, Locale.US);
85 87 *
86 88 * // Explicit argument indices may be used to re-order output.
87 89 * formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
88 90 * // -> " d c b a"
89 91 *
90 92 * // Optional locale as the first argument can be used to get
91 93 * // locale-specific formatting of numbers. The precision and width can be
92 94 * // given to round and align the value.
93 95 * formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E);
94 96 * // -> "e = +2,7183"
95 97 *
96 98 * // The '(' numeric flag may be used to format negative numbers with
97 99 * // parentheses rather than a minus sign. Group separators are
98 100 * // automatically inserted.
99 101 * formatter.format("Amount gained or lost since last statement: $ %(,.2f",
100 102 * balanceDelta);
101 103 * // -> "Amount gained or lost since last statement: $ (6,217.58)"
102 104 * </pre></blockquote>
103 105 *
104 106 * <p> Convenience methods for common formatting requests exist as illustrated
105 107 * by the following invocations:
106 108 *
107 109 * <blockquote><pre>
108 110 * // Writes a formatted string to System.out.
109 111 * System.out.format("Local time: %tT", Calendar.getInstance());
110 112 * // -> "Local time: 13:34:18"
111 113 *
112 114 * // Writes formatted output to System.err.
113 115 * System.err.printf("Unable to open file '%1$s': %2$s",
114 116 * fileName, exception.getMessage());
115 117 * // -> "Unable to open file 'food': No such file or directory"
116 118 * </pre></blockquote>
117 119 *
118 120 * <p> Like C's {@code sprintf(3)}, Strings may be formatted using the static
119 121 * method {@link String#format(String,Object...) String.format}:
120 122 *
121 123 * <blockquote><pre>
122 124 * // Format a string containing a date.
123 125 * import java.util.Calendar;
124 126 * import java.util.GregorianCalendar;
125 127 * import static java.util.Calendar.*;
126 128 *
127 129 * Calendar c = new GregorianCalendar(1995, MAY, 23);
128 130 * String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
129 131 * // -> s == "Duke's Birthday: May 23, 1995"
130 132 * </pre></blockquote>
131 133 *
132 134 * <h3><a name="org">Organization</a></h3>
133 135 *
134 136 * <p> This specification is divided into two sections. The first section, <a
135 137 * href="#summary">Summary</a>, covers the basic formatting concepts. This
136 138 * section is intended for users who want to get started quickly and are
137 139 * familiar with formatted printing in other programming languages. The second
138 140 * section, <a href="#detail">Details</a>, covers the specific implementation
139 141 * details. It is intended for users who want more precise specification of
140 142 * formatting behavior.
141 143 *
142 144 * <h3><a name="summary">Summary</a></h3>
143 145 *
144 146 * <p> This section is intended to provide a brief overview of formatting
145 147 * concepts. For precise behavioral details, refer to the <a
146 148 * href="#detail">Details</a> section.
147 149 *
148 150 * <h4><a name="syntax">Format String Syntax</a></h4>
149 151 *
150 152 * <p> Every method which produces formatted output requires a <i>format
151 153 * string</i> and an <i>argument list</i>. The format string is a {@link
152 154 * String} which may contain fixed text and one or more embedded <i>format
153 155 * specifiers</i>. Consider the following example:
154 156 *
155 157 * <blockquote><pre>
156 158 * Calendar c = ...;
157 159 * String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
158 160 * </pre></blockquote>
159 161 *
160 162 * This format string is the first argument to the {@code format} method. It
161 163 * contains three format specifiers "{@code %1$tm}", "{@code %1$te}", and
162 164 * "{@code %1$tY}" which indicate how the arguments should be processed and
163 165 * where they should be inserted in the text. The remaining portions of the
164 166 * format string are fixed text including {@code "Dukes Birthday: "} and any
165 167 * other spaces or punctuation.
166 168 *
167 169 * The argument list consists of all arguments passed to the method after the
168 170 * format string. In the above example, the argument list is of size one and
169 171 * consists of the {@link java.util.Calendar Calendar} object {@code c}.
170 172 *
171 173 * <ul>
172 174 *
173 175 * <li> The format specifiers for general, character, and numeric types have
174 176 * the following syntax:
175 177 *
176 178 * <blockquote><pre>
177 179 * %[argument_index$][flags][width][.precision]conversion
178 180 * </pre></blockquote>
179 181 *
180 182 * <p> The optional <i>argument_index</i> is a decimal integer indicating the
181 183 * position of the argument in the argument list. The first argument is
182 184 * referenced by "{@code 1$}", the second by "{@code 2$}", etc.
183 185 *
184 186 * <p> The optional <i>flags</i> is a set of characters that modify the output
185 187 * format. The set of valid flags depends on the conversion.
186 188 *
187 189 * <p> The optional <i>width</i> is a non-negative decimal integer indicating
188 190 * the minimum number of characters to be written to the output.
189 191 *
190 192 * <p> The optional <i>precision</i> is a non-negative decimal integer usually
191 193 * used to restrict the number of characters. The specific behavior depends on
192 194 * the conversion.
193 195 *
194 196 * <p> The required <i>conversion</i> is a character indicating how the
195 197 * argument should be formatted. The set of valid conversions for a given
196 198 * argument depends on the argument's data type.
197 199 *
198 200 * <li> The format specifiers for types which are used to represents dates and
199 201 * times have the following syntax:
200 202 *
201 203 * <blockquote><pre>
202 204 * %[argument_index$][flags][width]conversion
203 205 * </pre></blockquote>
204 206 *
205 207 * <p> The optional <i>argument_index</i>, <i>flags</i> and <i>width</i> are
206 208 * defined as above.
207 209 *
208 210 * <p> The required <i>conversion</i> is a two character sequence. The first
209 211 * character is {@code 't'} or {@code 'T'}. The second character indicates
210 212 * the format to be used. These characters are similar to but not completely
211 213 * identical to those defined by GNU {@code date} and POSIX
212 214 * {@code strftime(3c)}.
213 215 *
214 216 * <li> The format specifiers which do not correspond to arguments have the
215 217 * following syntax:
216 218 *
217 219 * <blockquote><pre>
218 220 * %[flags][width]conversion
219 221 * </pre></blockquote>
220 222 *
221 223 * <p> The optional <i>flags</i> and <i>width</i> is defined as above.
222 224 *
223 225 * <p> The required <i>conversion</i> is a character indicating content to be
224 226 * inserted in the output.
225 227 *
226 228 * </ul>
227 229 *
228 230 * <h4> Conversions </h4>
229 231 *
230 232 * <p> Conversions are divided into the following categories:
231 233 *
232 234 * <ol>
233 235 *
234 236 * <li> <b>General</b> - may be applied to any argument
235 237 * type
236 238 *
237 239 * <li> <b>Character</b> - may be applied to basic types which represent
238 240 * Unicode characters: {@code char}, {@link Character}, {@code byte}, {@link
239 241 * Byte}, {@code short}, and {@link Short}. This conversion may also be
240 242 * applied to the types {@code int} and {@link Integer} when {@link
241 243 * Character#isValidCodePoint} returns {@code true}
242 244 *
243 245 * <li> <b>Numeric</b>
244 246 *
245 247 * <ol>
246 248 *
247 249 * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
248 250 * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
249 251 * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
250 252 * BigInteger}
251 253 *
252 254 * <li><b>Floating Point</b> - may be applied to Java floating-point types:
253 255 * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
254 256 * java.math.BigDecimal BigDecimal}
255 257 *
256 258 * </ol>
257 259 *
258 260 * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
259 261 * encoding a date or time: {@code long}, {@link Long}, {@link Calendar}, and
260 262 * {@link Date}.
261 263 *
262 264 * <li> <b>Percent</b> - produces a literal {@code '%'}
263 265 * (<tt>'\u0025'</tt>)
264 266 *
265 267 * <li> <b>Line Separator</b> - produces the platform-specific line separator
266 268 *
267 269 * </ol>
268 270 *
269 271 * <p> The following table summarizes the supported conversions. Conversions
270 272 * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'},
271 273 * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'},
272 274 * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding
273 275 * lower-case conversion characters except that the result is converted to
274 276 * upper case according to the rules of the prevailing {@link java.util.Locale
275 277 * Locale}. The result is equivalent to the following invocation of {@link
276 278 * String#toUpperCase()}
277 279 *
278 280 * <pre>
279 281 * out.toUpperCase() </pre>
280 282 *
281 283 * <table cellpadding=5 summary="genConv">
282 284 *
283 285 * <tr><th valign="bottom"> Conversion
284 286 * <th valign="bottom"> Argument Category
285 287 * <th valign="bottom"> Description
286 288 *
287 289 * <tr><td valign="top"> {@code 'b'}, {@code 'B'}
288 290 * <td valign="top"> general
289 291 * <td> If the argument <i>arg</i> is {@code null}, then the result is
290 292 * "{@code false}". If <i>arg</i> is a {@code boolean} or {@link
291 293 * Boolean}, then the result is the string returned by {@link
292 294 * String#valueOf(boolean) String.valueOf(arg)}. Otherwise, the result is
293 295 * "true".
294 296 *
295 297 * <tr><td valign="top"> {@code 'h'}, {@code 'H'}
296 298 * <td valign="top"> general
297 299 * <td> If the argument <i>arg</i> is {@code null}, then the result is
298 300 * "{@code null}". Otherwise, the result is obtained by invoking
299 301 * {@code Integer.toHexString(arg.hashCode())}.
300 302 *
301 303 * <tr><td valign="top"> {@code 's'}, {@code 'S'}
302 304 * <td valign="top"> general
303 305 * <td> If the argument <i>arg</i> is {@code null}, then the result is
304 306 * "{@code null}". If <i>arg</i> implements {@link Formattable}, then
305 307 * {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the
306 308 * result is obtained by invoking {@code arg.toString()}.
307 309 *
308 310 * <tr><td valign="top">{@code 'c'}, {@code 'C'}
309 311 * <td valign="top"> character
310 312 * <td> The result is a Unicode character
311 313 *
312 314 * <tr><td valign="top">{@code 'd'}
313 315 * <td valign="top"> integral
314 316 * <td> The result is formatted as a decimal integer
315 317 *
316 318 * <tr><td valign="top">{@code 'o'}
317 319 * <td valign="top"> integral
318 320 * <td> The result is formatted as an octal integer
319 321 *
320 322 * <tr><td valign="top">{@code 'x'}, {@code 'X'}
321 323 * <td valign="top"> integral
322 324 * <td> The result is formatted as a hexadecimal integer
323 325 *
324 326 * <tr><td valign="top">{@code 'e'}, {@code 'E'}
325 327 * <td valign="top"> floating point
326 328 * <td> The result is formatted as a decimal number in computerized
327 329 * scientific notation
328 330 *
329 331 * <tr><td valign="top">{@code 'f'}
330 332 * <td valign="top"> floating point
331 333 * <td> The result is formatted as a decimal number
332 334 *
333 335 * <tr><td valign="top">{@code 'g'}, {@code 'G'}
334 336 * <td valign="top"> floating point
335 337 * <td> The result is formatted using computerized scientific notation or
336 338 * decimal format, depending on the precision and the value after rounding.
337 339 *
338 340 * <tr><td valign="top">{@code 'a'}, {@code 'A'}
339 341 * <td valign="top"> floating point
340 342 * <td> The result is formatted as a hexadecimal floating-point number with
341 343 * a significand and an exponent
342 344 *
343 345 * <tr><td valign="top">{@code 't'}, {@code 'T'}
344 346 * <td valign="top"> date/time
345 347 * <td> Prefix for date and time conversion characters. See <a
346 348 * href="#dt">Date/Time Conversions</a>.
347 349 *
348 350 * <tr><td valign="top">{@code '%'}
349 351 * <td valign="top"> percent
350 352 * <td> The result is a literal {@code '%'} (<tt>'\u0025'</tt>)
351 353 *
352 354 * <tr><td valign="top">{@code 'n'}
353 355 * <td valign="top"> line separator
354 356 * <td> The result is the platform-specific line separator
355 357 *
356 358 * </table>
357 359 *
358 360 * <p> Any characters not explicitly defined as conversions are illegal and are
359 361 * reserved for future extensions.
360 362 *
361 363 * <h4><a name="dt">Date/Time Conversions</a></h4>
362 364 *
363 365 * <p> The following date and time conversion suffix characters are defined for
364 366 * the {@code 't'} and {@code 'T'} conversions. The types are similar to but
365 367 * not completely identical to those defined by GNU {@code date} and POSIX
366 368 * {@code strftime(3c)}. Additional conversion types are provided to access
367 369 * Java-specific functionality (e.g. {@code 'L'} for milliseconds within the
368 370 * second).
369 371 *
370 372 * <p> The following conversion characters are used for formatting times:
371 373 *
372 374 * <table cellpadding=5 summary="time">
373 375 *
374 376 * <tr><td valign="top"> {@code 'H'}
375 377 * <td> Hour of the day for the 24-hour clock, formatted as two digits with
376 378 * a leading zero as necessary i.e. {@code 00 - 23}.
377 379 *
378 380 * <tr><td valign="top">{@code 'I'}
379 381 * <td> Hour for the 12-hour clock, formatted as two digits with a leading
380 382 * zero as necessary, i.e. {@code 01 - 12}.
381 383 *
382 384 * <tr><td valign="top">{@code 'k'}
383 385 * <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
384 386 *
385 387 * <tr><td valign="top">{@code 'l'}
386 388 * <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.
387 389 *
388 390 * <tr><td valign="top">{@code 'M'}
389 391 * <td> Minute within the hour formatted as two digits with a leading zero
390 392 * as necessary, i.e. {@code 00 - 59}.
391 393 *
392 394 * <tr><td valign="top">{@code 'S'}
393 395 * <td> Seconds within the minute, formatted as two digits with a leading
394 396 * zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
395 397 * value required to support leap seconds).
396 398 *
397 399 * <tr><td valign="top">{@code 'L'}
398 400 * <td> Millisecond within the second formatted as three digits with
399 401 * leading zeros as necessary, i.e. {@code 000 - 999}.
400 402 *
401 403 * <tr><td valign="top">{@code 'N'}
402 404 * <td> Nanosecond within the second, formatted as nine digits with leading
403 405 * zeros as necessary, i.e. {@code 000000000 - 999999999}.
404 406 *
405 407 * <tr><td valign="top">{@code 'p'}
406 408 * <td> Locale-specific {@linkplain
407 409 * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
408 410 * in lower case, e.g."{@code am}" or "{@code pm}". Use of the conversion
409 411 * prefix {@code 'T'} forces this output to upper case.
410 412 *
411 413 * <tr><td valign="top">{@code 'z'}
412 414 * <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>
413 415 * style numeric time zone offset from GMT, e.g. {@code -0800}. This
414 416 * value will be adjusted as necessary for Daylight Saving Time. For
415 417 * {@code long}, {@link Long}, and {@link Date} the time zone used is
416 418 * the {@linkplain TimeZone#getDefault() default time zone} for this
417 419 * instance of the Java virtual machine.
418 420 *
419 421 * <tr><td valign="top">{@code 'Z'}
420 422 * <td> A string representing the abbreviation for the time zone. This
421 423 * value will be adjusted as necessary for Daylight Saving Time. For
422 424 * {@code long}, {@link Long}, and {@link Date} the time zone used is
423 425 * the {@linkplain TimeZone#getDefault() default time zone} for this
424 426 * instance of the Java virtual machine. The Formatter's locale will
425 427 * supersede the locale of the argument (if any).
426 428 *
427 429 * <tr><td valign="top">{@code 's'}
428 430 * <td> Seconds since the beginning of the epoch starting at 1 January 1970
429 431 * {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
430 432 * {@code Long.MAX_VALUE/1000}.
431 433 *
432 434 * <tr><td valign="top">{@code 'Q'}
433 435 * <td> Milliseconds since the beginning of the epoch starting at 1 January
434 436 * 1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
435 437 * {@code Long.MAX_VALUE}.
436 438 *
437 439 * </table>
438 440 *
439 441 * <p> The following conversion characters are used for formatting dates:
440 442 *
441 443 * <table cellpadding=5 summary="date">
442 444 *
443 445 * <tr><td valign="top">{@code 'B'}
444 446 * <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
445 447 * full month name}, e.g. {@code "January"}, {@code "February"}.
446 448 *
447 449 * <tr><td valign="top">{@code 'b'}
448 450 * <td> Locale-specific {@linkplain
449 451 * java.text.DateFormatSymbols#getShortMonths abbreviated month name},
450 452 * e.g. {@code "Jan"}, {@code "Feb"}.
451 453 *
452 454 * <tr><td valign="top">{@code 'h'}
453 455 * <td> Same as {@code 'b'}.
454 456 *
455 457 * <tr><td valign="top">{@code 'A'}
456 458 * <td> Locale-specific full name of the {@linkplain
457 459 * java.text.DateFormatSymbols#getWeekdays day of the week},
458 460 * e.g. {@code "Sunday"}, {@code "Monday"}
459 461 *
460 462 * <tr><td valign="top">{@code 'a'}
461 463 * <td> Locale-specific short name of the {@linkplain
462 464 * java.text.DateFormatSymbols#getShortWeekdays day of the week},
463 465 * e.g. {@code "Sun"}, {@code "Mon"}
464 466 *
465 467 * <tr><td valign="top">{@code 'C'}
466 468 * <td> Four-digit year divided by {@code 100}, formatted as two digits
467 469 * with leading zero as necessary, i.e. {@code 00 - 99}
468 470 *
469 471 * <tr><td valign="top">{@code 'Y'}
470 472 * <td> Year, formatted as at least four digits with leading zeros as
471 473 * necessary, e.g. {@code 0092} equals {@code 92} CE for the Gregorian
472 474 * calendar.
473 475 *
474 476 * <tr><td valign="top">{@code 'y'}
475 477 * <td> Last two digits of the year, formatted with leading zeros as
476 478 * necessary, i.e. {@code 00 - 99}.
477 479 *
478 480 * <tr><td valign="top">{@code 'j'}
479 481 * <td> Day of year, formatted as three digits with leading zeros as
480 482 * necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
481 483 *
482 484 * <tr><td valign="top">{@code 'm'}
483 485 * <td> Month, formatted as two digits with leading zeros as necessary,
484 486 * i.e. {@code 01 - 13}.
485 487 *
486 488 * <tr><td valign="top">{@code 'd'}
487 489 * <td> Day of month, formatted as two digits with leading zeros as
488 490 * necessary, i.e. {@code 01 - 31}
489 491 *
490 492 * <tr><td valign="top">{@code 'e'}
491 493 * <td> Day of month, formatted as two digits, i.e. {@code 1 - 31}.
492 494 *
493 495 * </table>
494 496 *
495 497 * <p> The following conversion characters are used for formatting common
496 498 * date/time compositions.
497 499 *
498 500 * <table cellpadding=5 summary="composites">
499 501 *
500 502 * <tr><td valign="top">{@code 'R'}
501 503 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
502 504 *
503 505 * <tr><td valign="top">{@code 'T'}
504 506 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
505 507 *
506 508 * <tr><td valign="top">{@code 'r'}
507 509 * <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS %Tp"}.
508 510 * The location of the morning or afternoon marker ({@code '%Tp'}) may be
509 511 * locale-dependent.
510 512 *
511 513 * <tr><td valign="top">{@code 'D'}
512 514 * <td> Date formatted as {@code "%tm/%td/%ty"}.
513 515 *
514 516 * <tr><td valign="top">{@code 'F'}
515 517 * <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a>
516 518 * complete date formatted as {@code "%tY-%tm-%td"}.
517 519 *
518 520 * <tr><td valign="top">{@code 'c'}
519 521 * <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
520 522 * e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
521 523 *
522 524 * </table>
523 525 *
524 526 * <p> Any characters not explicitly defined as date/time conversion suffixes
525 527 * are illegal and are reserved for future extensions.
526 528 *
527 529 * <h4> Flags </h4>
528 530 *
529 531 * <p> The following table summarizes the supported flags. <i>y</i> means the
530 532 * flag is supported for the indicated argument types.
531 533 *
532 534 * <table cellpadding=5 summary="genConv">
533 535 *
534 536 * <tr><th valign="bottom"> Flag <th valign="bottom"> General
535 537 * <th valign="bottom"> Character <th valign="bottom"> Integral
536 538 * <th valign="bottom"> Floating Point
537 539 * <th valign="bottom"> Date/Time
538 540 * <th valign="bottom"> Description
539 541 *
540 542 * <tr><td> '-' <td align="center" valign="top"> y
541 543 * <td align="center" valign="top"> y
542 544 * <td align="center" valign="top"> y
543 545 * <td align="center" valign="top"> y
544 546 * <td align="center" valign="top"> y
545 547 * <td> The result will be left-justified.
546 548 *
547 549 * <tr><td> '#' <td align="center" valign="top"> y<sup>1</sup>
548 550 * <td align="center" valign="top"> -
549 551 * <td align="center" valign="top"> y<sup>3</sup>
550 552 * <td align="center" valign="top"> y
551 553 * <td align="center" valign="top"> -
552 554 * <td> The result should use a conversion-dependent alternate form
553 555 *
554 556 * <tr><td> '+' <td align="center" valign="top"> -
555 557 * <td align="center" valign="top"> -
556 558 * <td align="center" valign="top"> y<sup>4</sup>
557 559 * <td align="center" valign="top"> y
558 560 * <td align="center" valign="top"> -
559 561 * <td> The result will always include a sign
560 562 *
561 563 * <tr><td> ' ' <td align="center" valign="top"> -
562 564 * <td align="center" valign="top"> -
563 565 * <td align="center" valign="top"> y<sup>4</sup>
564 566 * <td align="center" valign="top"> y
565 567 * <td align="center" valign="top"> -
566 568 * <td> The result will include a leading space for positive values
567 569 *
568 570 * <tr><td> '0' <td align="center" valign="top"> -
569 571 * <td align="center" valign="top"> -
570 572 * <td align="center" valign="top"> y
571 573 * <td align="center" valign="top"> y
572 574 * <td align="center" valign="top"> -
573 575 * <td> The result will be zero-padded
574 576 *
575 577 * <tr><td> ',' <td align="center" valign="top"> -
576 578 * <td align="center" valign="top"> -
577 579 * <td align="center" valign="top"> y<sup>2</sup>
578 580 * <td align="center" valign="top"> y<sup>5</sup>
579 581 * <td align="center" valign="top"> -
580 582 * <td> The result will include locale-specific {@linkplain
581 583 * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators}
582 584 *
583 585 * <tr><td> '(' <td align="center" valign="top"> -
584 586 * <td align="center" valign="top"> -
585 587 * <td align="center" valign="top"> y<sup>4</sup>
586 588 * <td align="center" valign="top"> y<sup>5</sup>
587 589 * <td align="center"> -
588 590 * <td> The result will enclose negative numbers in parentheses
589 591 *
590 592 * </table>
591 593 *
592 594 * <p> <sup>1</sup> Depends on the definition of {@link Formattable}.
593 595 *
594 596 * <p> <sup>2</sup> For {@code 'd'} conversion only.
595 597 *
596 598 * <p> <sup>3</sup> For {@code 'o'}, {@code 'x'}, and {@code 'X'}
597 599 * conversions only.
598 600 *
599 601 * <p> <sup>4</sup> For {@code 'd'}, {@code 'o'}, {@code 'x'}, and
600 602 * {@code 'X'} conversions applied to {@link java.math.BigInteger BigInteger}
601 603 * or {@code 'd'} applied to {@code byte}, {@link Byte}, {@code short}, {@link
602 604 * Short}, {@code int} and {@link Integer}, {@code long}, and {@link Long}.
603 605 *
604 606 * <p> <sup>5</sup> For {@code 'e'}, {@code 'E'}, {@code 'f'},
605 607 * {@code 'g'}, and {@code 'G'} conversions only.
606 608 *
607 609 * <p> Any characters not explicitly defined as flags are illegal and are
608 610 * reserved for future extensions.
609 611 *
610 612 * <h4> Width </h4>
611 613 *
612 614 * <p> The width is the minimum number of characters to be written to the
613 615 * output. For the line separator conversion, width is not applicable; if it
614 616 * is provided, an exception will be thrown.
615 617 *
616 618 * <h4> Precision </h4>
617 619 *
618 620 * <p> For general argument types, the precision is the maximum number of
619 621 * characters to be written to the output.
620 622 *
621 623 * <p> For the floating-point conversions {@code 'e'}, {@code 'E'}, and
622 624 * {@code 'f'} the precision is the number of digits after the decimal
623 625 * separator. If the conversion is {@code 'g'} or {@code 'G'}, then the
624 626 * precision is the total number of digits in the resulting magnitude after
625 627 * rounding. If the conversion is {@code 'a'} or {@code 'A'}, then the
626 628 * precision must not be specified.
627 629 *
628 630 * <p> For character, integral, and date/time argument types and the percent
629 631 * and line separator conversions, the precision is not applicable; if a
630 632 * precision is provided, an exception will be thrown.
631 633 *
632 634 * <h4> Argument Index </h4>
633 635 *
634 636 * <p> The argument index is a decimal integer indicating the position of the
635 637 * argument in the argument list. The first argument is referenced by
636 638 * "{@code 1$}", the second by "{@code 2$}", etc.
637 639 *
638 640 * <p> Another way to reference arguments by position is to use the
639 641 * {@code '<'} (<tt>'\u003c'</tt>) flag, which causes the argument for
640 642 * the previous format specifier to be re-used. For example, the following two
641 643 * statements would produce identical strings:
642 644 *
643 645 * <blockquote><pre>
644 646 * Calendar c = ...;
645 647 * String s1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
646 648 *
647 649 * String s2 = String.format("Duke's Birthday: %1$tm %<te,%<tY", c);
648 650 * </pre></blockquote>
649 651 *
650 652 * <hr>
651 653 * <h3><a name="detail">Details</a></h3>
652 654 *
653 655 * <p> This section is intended to provide behavioral details for formatting,
654 656 * including conditions and exceptions, supported data types, localization, and
655 657 * interactions between flags, conversions, and data types. For an overview of
656 658 * formatting concepts, refer to the <a href="#summary">Summary</a>
657 659 *
658 660 * <p> Any characters not explicitly defined as conversions, date/time
659 661 * conversion suffixes, or flags are illegal and are reserved for
660 662 * future extensions. Use of such a character in a format string will
661 663 * cause an {@link UnknownFormatConversionException} or {@link
662 664 * UnknownFormatFlagsException} to be thrown.
663 665 *
664 666 * <p> If the format specifier contains a width or precision with an invalid
665 667 * value or which is otherwise unsupported, then a {@link
666 668 * IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
667 669 * respectively will be thrown.
668 670 *
669 671 * <p> If a format specifier contains a conversion character that is not
670 672 * applicable to the corresponding argument, then an {@link
671 673 * IllegalFormatConversionException} will be thrown.
672 674 *
673 675 * <p> All specified exceptions may be thrown by any of the {@code format}
674 676 * methods of {@code Formatter} as well as by any {@code format} convenience
675 677 * methods such as {@link String#format(String,Object...) String.format} and
676 678 * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}.
677 679 *
678 680 * <p> Conversions denoted by an upper-case character (i.e. {@code 'B'},
679 681 * {@code 'H'}, {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'},
680 682 * {@code 'G'}, {@code 'A'}, and {@code 'T'}) are the same as those for the
681 683 * corresponding lower-case conversion characters except that the result is
682 684 * converted to upper case according to the rules of the prevailing {@link
683 685 * java.util.Locale Locale}. The result is equivalent to the following
684 686 * invocation of {@link String#toUpperCase()}
685 687 *
686 688 * <pre>
687 689 * out.toUpperCase() </pre>
688 690 *
689 691 * <h4><a name="dgen">General</a></h4>
690 692 *
691 693 * <p> The following general conversions may be applied to any argument type:
692 694 *
693 695 * <table cellpadding=5 summary="dgConv">
694 696 *
695 697 * <tr><td valign="top"> {@code 'b'}
696 698 * <td valign="top"> <tt>'\u0062'</tt>
697 699 * <td> Produces either "{@code true}" or "{@code false}" as returned by
698 700 * {@link Boolean#toString(boolean)}.
699 701 *
700 702 * <p> If the argument is {@code null}, then the result is
701 703 * "{@code false}". If the argument is a {@code boolean} or {@link
702 704 * Boolean}, then the result is the string returned by {@link
703 705 * String#valueOf(boolean) String.valueOf()}. Otherwise, the result is
704 706 * "{@code true}".
705 707 *
706 708 * <p> If the {@code '#'} flag is given, then a {@link
707 709 * FormatFlagsConversionMismatchException} will be thrown.
708 710 *
709 711 * <tr><td valign="top"> {@code 'B'}
710 712 * <td valign="top"> <tt>'\u0042'</tt>
711 713 * <td> The upper-case variant of {@code 'b'}.
712 714 *
713 715 * <tr><td valign="top"> {@code 'h'}
714 716 * <td valign="top"> <tt>'\u0068'</tt>
715 717 * <td> Produces a string representing the hash code value of the object.
716 718 *
717 719 * <p> If the argument, <i>arg</i> is {@code null}, then the
718 720 * result is "{@code null}". Otherwise, the result is obtained
719 721 * by invoking {@code Integer.toHexString(arg.hashCode())}.
720 722 *
721 723 * <p> If the {@code '#'} flag is given, then a {@link
722 724 * FormatFlagsConversionMismatchException} will be thrown.
723 725 *
724 726 * <tr><td valign="top"> {@code 'H'}
725 727 * <td valign="top"> <tt>'\u0048'</tt>
726 728 * <td> The upper-case variant of {@code 'h'}.
727 729 *
728 730 * <tr><td valign="top"> {@code 's'}
729 731 * <td valign="top"> <tt>'\u0073'</tt>
730 732 * <td> Produces a string.
731 733 *
732 734 * <p> If the argument is {@code null}, then the result is
733 735 * "{@code null}". If the argument implements {@link Formattable}, then
734 736 * its {@link Formattable#formatTo formatTo} method is invoked.
735 737 * Otherwise, the result is obtained by invoking the argument's
736 738 * {@code toString()} method.
737 739 *
738 740 * <p> If the {@code '#'} flag is given and the argument is not a {@link
739 741 * Formattable} , then a {@link FormatFlagsConversionMismatchException}
740 742 * will be thrown.
741 743 *
742 744 * <tr><td valign="top"> {@code 'S'}
743 745 * <td valign="top"> <tt>'\u0053'</tt>
744 746 * <td> The upper-case variant of {@code 's'}.
745 747 *
746 748 * </table>
747 749 *
748 750 * <p> The following <a name="dFlags">flags</a> apply to general conversions:
749 751 *
750 752 * <table cellpadding=5 summary="dFlags">
751 753 *
752 754 * <tr><td valign="top"> {@code '-'}
753 755 * <td valign="top"> <tt>'\u002d'</tt>
754 756 * <td> Left justifies the output. Spaces (<tt>'\u0020'</tt>) will be
755 757 * added at the end of the converted value as required to fill the minimum
756 758 * width of the field. If the width is not provided, then a {@link
757 759 * MissingFormatWidthException} will be thrown. If this flag is not given
758 760 * then the output will be right-justified.
759 761 *
760 762 * <tr><td valign="top"> {@code '#'}
761 763 * <td valign="top"> <tt>'\u0023'</tt>
762 764 * <td> Requires the output use an alternate form. The definition of the
763 765 * form is specified by the conversion.
764 766 *
765 767 * </table>
766 768 *
767 769 * <p> The <a name="genWidth">width</a> is the minimum number of characters to
768 770 * be written to the
769 771 * output. If the length of the converted value is less than the width then
770 772 * the output will be padded by <tt>' '</tt> (<tt>'\u0020'</tt>)
771 773 * until the total number of characters equals the width. The padding is on
772 774 * the left by default. If the {@code '-'} flag is given, then the padding
773 775 * will be on the right. If the width is not specified then there is no
774 776 * minimum.
775 777 *
776 778 * <p> The precision is the maximum number of characters to be written to the
777 779 * output. The precision is applied before the width, thus the output will be
778 780 * truncated to {@code precision} characters even if the width is greater than
779 781 * the precision. If the precision is not specified then there is no explicit
780 782 * limit on the number of characters.
781 783 *
782 784 * <h4><a name="dchar">Character</a></h4>
783 785 *
784 786 * This conversion may be applied to {@code char} and {@link Character}. It
785 787 * may also be applied to the types {@code byte}, {@link Byte},
786 788 * {@code short}, and {@link Short}, {@code int} and {@link Integer} when
787 789 * {@link Character#isValidCodePoint} returns {@code true}. If it returns
788 790 * {@code false} then an {@link IllegalFormatCodePointException} will be
789 791 * thrown.
790 792 *
791 793 * <table cellpadding=5 summary="charConv">
792 794 *
793 795 * <tr><td valign="top"> {@code 'c'}
794 796 * <td valign="top"> <tt>'\u0063'</tt>
795 797 * <td> Formats the argument as a Unicode character as described in <a
796 798 * href="../lang/Character.html#unicode">Unicode Character
797 799 * Representation</a>. This may be more than one 16-bit {@code char} in
798 800 * the case where the argument represents a supplementary character.
799 801 *
800 802 * <p> If the {@code '#'} flag is given, then a {@link
801 803 * FormatFlagsConversionMismatchException} will be thrown.
802 804 *
803 805 * <tr><td valign="top"> {@code 'C'}
804 806 * <td valign="top"> <tt>'\u0043'</tt>
805 807 * <td> The upper-case variant of {@code 'c'}.
806 808 *
807 809 * </table>
808 810 *
809 811 * <p> The {@code '-'} flag defined for <a href="#dFlags">General
810 812 * conversions</a> applies. If the {@code '#'} flag is given, then a {@link
811 813 * FormatFlagsConversionMismatchException} will be thrown.
812 814 *
813 815 * <p> The width is defined as for <a href="#genWidth">General conversions</a>.
814 816 *
815 817 * <p> The precision is not applicable. If the precision is specified then an
816 818 * {@link IllegalFormatPrecisionException} will be thrown.
817 819 *
818 820 * <h4><a name="dnum">Numeric</a></h4>
819 821 *
820 822 * <p> Numeric conversions are divided into the following categories:
821 823 *
822 824 * <ol>
823 825 *
824 826 * <li> <a href="#dnint"><b>Byte, Short, Integer, and Long</b></a>
825 827 *
826 828 * <li> <a href="#dnbint"><b>BigInteger</b></a>
827 829 *
828 830 * <li> <a href="#dndec"><b>Float and Double</b></a>
829 831 *
830 832 * <li> <a href="#dndec"><b>BigDecimal</b></a>
831 833 *
832 834 * </ol>
833 835 *
834 836 * <p> Numeric types will be formatted according to the following algorithm:
835 837 *
836 838 * <p><b><a name="l10n algorithm"> Number Localization Algorithm</a></b>
837 839 *
838 840 * <p> After digits are obtained for the integer part, fractional part, and
839 841 * exponent (as appropriate for the data type), the following transformation
840 842 * is applied:
841 843 *
842 844 * <ol>
843 845 *
844 846 * <li> Each digit character <i>d</i> in the string is replaced by a
845 847 * locale-specific digit computed relative to the current locale's
846 848 * {@linkplain java.text.DecimalFormatSymbols#getZeroDigit() zero digit}
847 849 * <i>z</i>; that is <i>d - </i> {@code '0'}
848 850 * <i> + z</i>.
849 851 *
850 852 * <li> If a decimal separator is present, a locale-specific {@linkplain
851 853 * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is
852 854 * substituted.
853 855 *
854 856 * <li> If the {@code ','} (<tt>'\u002c'</tt>)
855 857 * <a name="l10n group">flag</a> is given, then the locale-specific {@linkplain
856 858 * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is
857 859 * inserted by scanning the integer part of the string from least significant
858 860 * to most significant digits and inserting a separator at intervals defined by
859 861 * the locale's {@linkplain java.text.DecimalFormat#getGroupingSize() grouping
860 862 * size}.
861 863 *
862 864 * <li> If the {@code '0'} flag is given, then the locale-specific {@linkplain
863 865 * java.text.DecimalFormatSymbols#getZeroDigit() zero digits} are inserted
864 866 * after the sign character, if any, and before the first non-zero digit, until
865 867 * the length of the string is equal to the requested field width.
866 868 *
867 869 * <li> If the value is negative and the {@code '('} flag is given, then a
868 870 * {@code '('} (<tt>'\u0028'</tt>) is prepended and a {@code ')'}
869 871 * (<tt>'\u0029'</tt>) is appended.
870 872 *
871 873 * <li> If the value is negative (or floating-point negative zero) and
872 874 * {@code '('} flag is not given, then a {@code '-'} (<tt>'\u002d'</tt>)
873 875 * is prepended.
874 876 *
875 877 * <li> If the {@code '+'} flag is given and the value is positive or zero (or
876 878 * floating-point positive zero), then a {@code '+'} (<tt>'\u002b'</tt>)
877 879 * will be prepended.
878 880 *
879 881 * </ol>
880 882 *
881 883 * <p> If the value is NaN or positive infinity the literal strings "NaN" or
882 884 * "Infinity" respectively, will be output. If the value is negative infinity,
883 885 * then the output will be "(Infinity)" if the {@code '('} flag is given
884 886 * otherwise the output will be "-Infinity". These values are not localized.
885 887 *
886 888 * <p><a name="dnint"><b> Byte, Short, Integer, and Long </b></a>
887 889 *
888 890 * <p> The following conversions may be applied to {@code byte}, {@link Byte},
889 891 * {@code short}, {@link Short}, {@code int} and {@link Integer},
890 892 * {@code long}, and {@link Long}.
891 893 *
892 894 * <table cellpadding=5 summary="IntConv">
893 895 *
894 896 * <tr><td valign="top"> {@code 'd'}
895 897 * <td valign="top"> <tt>'\u0054'</tt>
896 898 * <td> Formats the argument as a decimal integer. The <a
897 899 * href="#l10n algorithm">localization algorithm</a> is applied.
898 900 *
899 901 * <p> If the {@code '0'} flag is given and the value is negative, then
900 902 * the zero padding will occur after the sign.
901 903 *
902 904 * <p> If the {@code '#'} flag is given then a {@link
903 905 * FormatFlagsConversionMismatchException} will be thrown.
904 906 *
905 907 * <tr><td valign="top"> {@code 'o'}
906 908 * <td valign="top"> <tt>'\u006f'</tt>
907 909 * <td> Formats the argument as an integer in base eight. No localization
908 910 * is applied.
909 911 *
910 912 * <p> If <i>x</i> is negative then the result will be an unsigned value
911 913 * generated by adding 2<sup>n</sup> to the value where {@code n} is the
912 914 * number of bits in the type as returned by the static {@code SIZE} field
913 915 * in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
914 916 * {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
915 917 * classes as appropriate.
916 918 *
917 919 * <p> If the {@code '#'} flag is given then the output will always begin
918 920 * with the radix indicator {@code '0'}.
919 921 *
920 922 * <p> If the {@code '0'} flag is given then the output will be padded
921 923 * with leading zeros to the field width following any indication of sign.
922 924 *
923 925 * <p> If {@code '('}, {@code '+'}, '  ', or {@code ','} flags
924 926 * are given then a {@link FormatFlagsConversionMismatchException} will be
925 927 * thrown.
926 928 *
927 929 * <tr><td valign="top"> {@code 'x'}
928 930 * <td valign="top"> <tt>'\u0078'</tt>
929 931 * <td> Formats the argument as an integer in base sixteen. No
930 932 * localization is applied.
931 933 *
932 934 * <p> If <i>x</i> is negative then the result will be an unsigned value
933 935 * generated by adding 2<sup>n</sup> to the value where {@code n} is the
934 936 * number of bits in the type as returned by the static {@code SIZE} field
935 937 * in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
936 938 * {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
937 939 * classes as appropriate.
938 940 *
939 941 * <p> If the {@code '#'} flag is given then the output will always begin
940 942 * with the radix indicator {@code "0x"}.
941 943 *
942 944 * <p> If the {@code '0'} flag is given then the output will be padded to
943 945 * the field width with leading zeros after the radix indicator or sign (if
944 946 * present).
945 947 *
946 948 * <p> If {@code '('}, <tt>' '</tt>, {@code '+'}, or
947 949 * {@code ','} flags are given then a {@link
948 950 * FormatFlagsConversionMismatchException} will be thrown.
949 951 *
950 952 * <tr><td valign="top"> {@code 'X'}
951 953 * <td valign="top"> <tt>'\u0058'</tt>
952 954 * <td> The upper-case variant of {@code 'x'}. The entire string
953 955 * representing the number will be converted to {@linkplain
954 956 * String#toUpperCase upper case} including the {@code 'x'} (if any) and
955 957 * all hexadecimal digits {@code 'a'} - {@code 'f'}
956 958 * (<tt>'\u0061'</tt> - <tt>'\u0066'</tt>).
957 959 *
958 960 * </table>
959 961 *
960 962 * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
961 963 * both the {@code '#'} and the {@code '0'} flags are given, then result will
962 964 * contain the radix indicator ({@code '0'} for octal and {@code "0x"} or
963 965 * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
964 966 * and the value.
965 967 *
966 968 * <p> If the {@code '-'} flag is not given, then the space padding will occur
967 969 * before the sign.
968 970 *
969 971 * <p> The following <a name="intFlags">flags</a> apply to numeric integral
970 972 * conversions:
971 973 *
972 974 * <table cellpadding=5 summary="intFlags">
973 975 *
974 976 * <tr><td valign="top"> {@code '+'}
975 977 * <td valign="top"> <tt>'\u002b'</tt>
976 978 * <td> Requires the output to include a positive sign for all positive
977 979 * numbers. If this flag is not given then only negative values will
978 980 * include a sign.
979 981 *
980 982 * <p> If both the {@code '+'} and <tt>' '</tt> flags are given
981 983 * then an {@link IllegalFormatFlagsException} will be thrown.
982 984 *
983 985 * <tr><td valign="top"> <tt>' '</tt>
984 986 * <td valign="top"> <tt>'\u0020'</tt>
985 987 * <td> Requires the output to include a single extra space
986 988 * (<tt>'\u0020'</tt>) for non-negative values.
987 989 *
988 990 * <p> If both the {@code '+'} and <tt>' '</tt> flags are given
989 991 * then an {@link IllegalFormatFlagsException} will be thrown.
990 992 *
991 993 * <tr><td valign="top"> {@code '0'}
992 994 * <td valign="top"> <tt>'\u0030'</tt>
993 995 * <td> Requires the output to be padded with leading {@linkplain
994 996 * java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field
995 997 * width following any sign or radix indicator except when converting NaN
996 998 * or infinity. If the width is not provided, then a {@link
997 999 * MissingFormatWidthException} will be thrown.
998 1000 *
999 1001 * <p> If both the {@code '-'} and {@code '0'} flags are given then an
1000 1002 * {@link IllegalFormatFlagsException} will be thrown.
1001 1003 *
1002 1004 * <tr><td valign="top"> {@code ','}
1003 1005 * <td valign="top"> <tt>'\u002c'</tt>
1004 1006 * <td> Requires the output to include the locale-specific {@linkplain
1005 1007 * java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as
1006 1008 * described in the <a href="#l10n group">"group" section</a> of the
1007 1009 * localization algorithm.
1008 1010 *
1009 1011 * <tr><td valign="top"> {@code '('}
1010 1012 * <td valign="top"> <tt>'\u0028'</tt>
1011 1013 * <td> Requires the output to prepend a {@code '('}
1012 1014 * (<tt>'\u0028'</tt>) and append a {@code ')'}
1013 1015 * (<tt>'\u0029'</tt>) to negative values.
1014 1016 *
1015 1017 * </table>
1016 1018 *
1017 1019 * <p> If no <a name="intdFlags">flags</a> are given the default formatting is
1018 1020 * as follows:
1019 1021 *
1020 1022 * <ul>
1021 1023 *
1022 1024 * <li> The output is right-justified within the {@code width}
1023 1025 *
1024 1026 * <li> Negative numbers begin with a {@code '-'} (<tt>'\u002d'</tt>)
1025 1027 *
1026 1028 * <li> Positive numbers and zero do not include a sign or extra leading
1027 1029 * space
1028 1030 *
1029 1031 * <li> No grouping separators are included
1030 1032 *
1031 1033 * </ul>
1032 1034 *
1033 1035 * <p> The <a name="intWidth">width</a> is the minimum number of characters to
1034 1036 * be written to the output. This includes any signs, digits, grouping
1035 1037 * separators, radix indicator, and parentheses. If the length of the
1036 1038 * converted value is less than the width then the output will be padded by
1037 1039 * spaces (<tt>'\u0020'</tt>) until the total number of characters equals
1038 1040 * width. The padding is on the left by default. If {@code '-'} flag is
1039 1041 * given then the padding will be on the right. If width is not specified then
1040 1042 * there is no minimum.
1041 1043 *
1042 1044 * <p> The precision is not applicable. If precision is specified then an
1043 1045 * {@link IllegalFormatPrecisionException} will be thrown.
1044 1046 *
1045 1047 * <p><a name="dnbint"><b> BigInteger </b></a>
1046 1048 *
1047 1049 * <p> The following conversions may be applied to {@link
1048 1050 * java.math.BigInteger}.
1049 1051 *
1050 1052 * <table cellpadding=5 summary="BIntConv">
1051 1053 *
1052 1054 * <tr><td valign="top"> {@code 'd'}
1053 1055 * <td valign="top"> <tt>'\u0054'</tt>
1054 1056 * <td> Requires the output to be formatted as a decimal integer. The <a
1055 1057 * href="#l10n algorithm">localization algorithm</a> is applied.
1056 1058 *
1057 1059 * <p> If the {@code '#'} flag is given {@link
1058 1060 * FormatFlagsConversionMismatchException} will be thrown.
1059 1061 *
1060 1062 * <tr><td valign="top"> {@code 'o'}
1061 1063 * <td valign="top"> <tt>'\u006f'</tt>
1062 1064 * <td> Requires the output to be formatted as an integer in base eight.
1063 1065 * No localization is applied.
1064 1066 *
1065 1067 * <p> If <i>x</i> is negative then the result will be a signed value
1066 1068 * beginning with {@code '-'} (<tt>'\u002d'</tt>). Signed output is
1067 1069 * allowed for this type because unlike the primitive types it is not
1068 1070 * possible to create an unsigned equivalent without assuming an explicit
1069 1071 * data-type size.
1070 1072 *
1071 1073 * <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
1072 1074 * then the result will begin with {@code '+'} (<tt>'\u002b'</tt>).
1073 1075 *
1074 1076 * <p> If the {@code '#'} flag is given then the output will always begin
1075 1077 * with {@code '0'} prefix.
1076 1078 *
1077 1079 * <p> If the {@code '0'} flag is given then the output will be padded
1078 1080 * with leading zeros to the field width following any indication of sign.
1079 1081 *
1080 1082 * <p> If the {@code ','} flag is given then a {@link
1081 1083 * FormatFlagsConversionMismatchException} will be thrown.
1082 1084 *
1083 1085 * <tr><td valign="top"> {@code 'x'}
1084 1086 * <td valign="top"> <tt>'\u0078'</tt>
1085 1087 * <td> Requires the output to be formatted as an integer in base
1086 1088 * sixteen. No localization is applied.
1087 1089 *
1088 1090 * <p> If <i>x</i> is negative then the result will be a signed value
1089 1091 * beginning with {@code '-'} (<tt>'\u002d'</tt>). Signed output is
1090 1092 * allowed for this type because unlike the primitive types it is not
1091 1093 * possible to create an unsigned equivalent without assuming an explicit
1092 1094 * data-type size.
1093 1095 *
1094 1096 * <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
1095 1097 * then the result will begin with {@code '+'} (<tt>'\u002b'</tt>).
1096 1098 *
1097 1099 * <p> If the {@code '#'} flag is given then the output will always begin
1098 1100 * with the radix indicator {@code "0x"}.
1099 1101 *
1100 1102 * <p> If the {@code '0'} flag is given then the output will be padded to
1101 1103 * the field width with leading zeros after the radix indicator or sign (if
1102 1104 * present).
1103 1105 *
1104 1106 * <p> If the {@code ','} flag is given then a {@link
1105 1107 * FormatFlagsConversionMismatchException} will be thrown.
1106 1108 *
1107 1109 * <tr><td valign="top"> {@code 'X'}
1108 1110 * <td valign="top"> <tt>'\u0058'</tt>
1109 1111 * <td> The upper-case variant of {@code 'x'}. The entire string
1110 1112 * representing the number will be converted to {@linkplain
1111 1113 * String#toUpperCase upper case} including the {@code 'x'} (if any) and
1112 1114 * all hexadecimal digits {@code 'a'} - {@code 'f'}
1113 1115 * (<tt>'\u0061'</tt> - <tt>'\u0066'</tt>).
1114 1116 *
1115 1117 * </table>
1116 1118 *
1117 1119 * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
1118 1120 * both the {@code '#'} and the {@code '0'} flags are given, then result will
1119 1121 * contain the base indicator ({@code '0'} for octal and {@code "0x"} or
1120 1122 * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
1121 1123 * and the value.
1122 1124 *
1123 1125 * <p> If the {@code '0'} flag is given and the value is negative, then the
1124 1126 * zero padding will occur after the sign.
1125 1127 *
1126 1128 * <p> If the {@code '-'} flag is not given, then the space padding will occur
1127 1129 * before the sign.
1128 1130 *
1129 1131 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
1130 1132 * Long apply. The <a href="#intdFlags">default behavior</a> when no flags are
1131 1133 * given is the same as for Byte, Short, Integer, and Long.
1132 1134 *
1133 1135 * <p> The specification of <a href="#intWidth">width</a> is the same as
1134 1136 * defined for Byte, Short, Integer, and Long.
1135 1137 *
1136 1138 * <p> The precision is not applicable. If precision is specified then an
1137 1139 * {@link IllegalFormatPrecisionException} will be thrown.
1138 1140 *
1139 1141 * <p><a name="dndec"><b> Float and Double</b></a>
1140 1142 *
1141 1143 * <p> The following conversions may be applied to {@code float}, {@link
1142 1144 * Float}, {@code double} and {@link Double}.
1143 1145 *
1144 1146 * <table cellpadding=5 summary="floatConv">
1145 1147 *
1146 1148 * <tr><td valign="top"> {@code 'e'}
1147 1149 * <td valign="top"> <tt>'\u0065'</tt>
1148 1150 * <td> Requires the output to be formatted using <a
1149 1151 * name="scientific">computerized scientific notation</a>. The <a
1150 1152 * href="#l10n algorithm">localization algorithm</a> is applied.
1151 1153 *
1152 1154 * <p> The formatting of the magnitude <i>m</i> depends upon its value.
1153 1155 *
1154 1156 * <p> If <i>m</i> is NaN or infinite, the literal strings "NaN" or
1155 1157 * "Infinity", respectively, will be output. These values are not
1156 1158 * localized.
1157 1159 *
1158 1160 * <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
1159 1161 * will be {@code "+00"}.
1160 1162 *
1161 1163 * <p> Otherwise, the result is a string that represents the sign and
1162 1164 * magnitude (absolute value) of the argument. The formatting of the sign
1163 1165 * is described in the <a href="#l10n algorithm">localization
1164 1166 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
1165 1167 * value.
1166 1168 *
1167 1169 * <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
1168 1170 * <= <i>m</i> < 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
1169 1171 * mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
1170 1172 * that 1 <= <i>a</i> < 10. The magnitude is then represented as the
1171 1173 * integer part of <i>a</i>, as a single decimal digit, followed by the
1172 1174 * decimal separator followed by decimal digits representing the fractional
1173 1175 * part of <i>a</i>, followed by the exponent symbol {@code 'e'}
1174 1176 * (<tt>'\u0065'</tt>), followed by the sign of the exponent, followed
1175 1177 * by a representation of <i>n</i> as a decimal integer, as produced by the
1176 1178 * method {@link Long#toString(long, int)}, and zero-padded to include at
1177 1179 * least two digits.
1178 1180 *
1179 1181 * <p> The number of digits in the result for the fractional part of
1180 1182 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
1181 1183 * specified then the default value is {@code 6}. If the precision is less
1182 1184 * than the number of digits which would appear after the decimal point in
1183 1185 * the string returned by {@link Float#toString(float)} or {@link
1184 1186 * Double#toString(double)} respectively, then the value will be rounded
1185 1187 * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
1186 1188 * algorithm}. Otherwise, zeros may be appended to reach the precision.
1187 1189 * For a canonical representation of the value, use {@link
1188 1190 * Float#toString(float)} or {@link Double#toString(double)} as
1189 1191 * appropriate.
1190 1192 *
1191 1193 * <p>If the {@code ','} flag is given, then an {@link
1192 1194 * FormatFlagsConversionMismatchException} will be thrown.
1193 1195 *
1194 1196 * <tr><td valign="top"> {@code 'E'}
1195 1197 * <td valign="top"> <tt>'\u0045'</tt>
1196 1198 * <td> The upper-case variant of {@code 'e'}. The exponent symbol
1197 1199 * will be {@code 'E'} (<tt>'\u0045'</tt>).
1198 1200 *
1199 1201 * <tr><td valign="top"> {@code 'g'}
1200 1202 * <td valign="top"> <tt>'\u0067'</tt>
1201 1203 * <td> Requires the output to be formatted in general scientific notation
1202 1204 * as described below. The <a href="#l10n algorithm">localization
1203 1205 * algorithm</a> is applied.
1204 1206 *
1205 1207 * <p> After rounding for the precision, the formatting of the resulting
1206 1208 * magnitude <i>m</i> depends on its value.
1207 1209 *
1208 1210 * <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
1209 1211 * than 10<sup>precision</sup> then it is represented in <i><a
1210 1212 * href="#decimal">decimal format</a></i>.
1211 1213 *
1212 1214 * <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
1213 1215 * 10<sup>precision</sup>, then it is represented in <i><a
1214 1216 * href="#scientific">computerized scientific notation</a></i>.
1215 1217 *
1216 1218 * <p> The total number of significant digits in <i>m</i> is equal to the
1217 1219 * precision. If the precision is not specified, then the default value is
1218 1220 * {@code 6}. If the precision is {@code 0}, then it is taken to be
1219 1221 * {@code 1}.
1220 1222 *
1221 1223 * <p> If the {@code '#'} flag is given then an {@link
1222 1224 * FormatFlagsConversionMismatchException} will be thrown.
1223 1225 *
1224 1226 * <tr><td valign="top"> {@code 'G'}
1225 1227 * <td valign="top"> <tt>'\u0047'</tt>
1226 1228 * <td> The upper-case variant of {@code 'g'}.
1227 1229 *
1228 1230 * <tr><td valign="top"> {@code 'f'}
1229 1231 * <td valign="top"> <tt>'\u0066'</tt>
1230 1232 * <td> Requires the output to be formatted using <a name="decimal">decimal
1231 1233 * format</a>. The <a href="#l10n algorithm">localization algorithm</a> is
1232 1234 * applied.
1233 1235 *
1234 1236 * <p> The result is a string that represents the sign and magnitude
1235 1237 * (absolute value) of the argument. The formatting of the sign is
1236 1238 * described in the <a href="#l10n algorithm">localization
1237 1239 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
1238 1240 * value.
1239 1241 *
1240 1242 * <p> If <i>m</i> NaN or infinite, the literal strings "NaN" or
1241 1243 * "Infinity", respectively, will be output. These values are not
1242 1244 * localized.
1243 1245 *
1244 1246 * <p> The magnitude is formatted as the integer part of <i>m</i>, with no
1245 1247 * leading zeroes, followed by the decimal separator followed by one or
1246 1248 * more decimal digits representing the fractional part of <i>m</i>.
1247 1249 *
1248 1250 * <p> The number of digits in the result for the fractional part of
1249 1251 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
1250 1252 * specified then the default value is {@code 6}. If the precision is less
1251 1253 * than the number of digits which would appear after the decimal point in
1252 1254 * the string returned by {@link Float#toString(float)} or {@link
1253 1255 * Double#toString(double)} respectively, then the value will be rounded
1254 1256 * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
1255 1257 * algorithm}. Otherwise, zeros may be appended to reach the precision.
1256 1258 * For a canonical representation of the value, use {@link
1257 1259 * Float#toString(float)} or {@link Double#toString(double)} as
1258 1260 * appropriate.
1259 1261 *
1260 1262 * <tr><td valign="top"> {@code 'a'}
1261 1263 * <td valign="top"> <tt>'\u0061'</tt>
1262 1264 * <td> Requires the output to be formatted in hexadecimal exponential
1263 1265 * form. No localization is applied.
1264 1266 *
1265 1267 * <p> The result is a string that represents the sign and magnitude
1266 1268 * (absolute value) of the argument <i>x</i>.
1267 1269 *
1268 1270 * <p> If <i>x</i> is negative or a negative-zero value then the result
1269 1271 * will begin with {@code '-'} (<tt>'\u002d'</tt>).
1270 1272 *
1271 1273 * <p> If <i>x</i> is positive or a positive-zero value and the
1272 1274 * {@code '+'} flag is given then the result will begin with {@code '+'}
1273 1275 * (<tt>'\u002b'</tt>).
1274 1276 *
1275 1277 * <p> The formatting of the magnitude <i>m</i> depends upon its value.
1276 1278 *
1277 1279 * <ul>
1278 1280 *
1279 1281 * <li> If the value is NaN or infinite, the literal strings "NaN" or
1280 1282 * "Infinity", respectively, will be output.
1281 1283 *
1282 1284 * <li> If <i>m</i> is zero then it is represented by the string
1283 1285 * {@code "0x0.0p0"}.
1284 1286 *
1285 1287 * <li> If <i>m</i> is a {@code double} value with a normalized
1286 1288 * representation then substrings are used to represent the significand and
1287 1289 * exponent fields. The significand is represented by the characters
1288 1290 * {@code "0x1."} followed by the hexadecimal representation of the rest
1289 1291 * of the significand as a fraction. The exponent is represented by
1290 1292 * {@code 'p'} (<tt>'\u0070'</tt>) followed by a decimal string of the
1291 1293 * unbiased exponent as if produced by invoking {@link
1292 1294 * Integer#toString(int) Integer.toString} on the exponent value.
1293 1295 *
1294 1296 * <li> If <i>m</i> is a {@code double} value with a subnormal
1295 1297 * representation then the significand is represented by the characters
1296 1298 * {@code '0x0.'} followed by the hexadecimal representation of the rest
1297 1299 * of the significand as a fraction. The exponent is represented by
1298 1300 * {@code 'p-1022'}. Note that there must be at least one nonzero digit
1299 1301 * in a subnormal significand.
1300 1302 *
1301 1303 * </ul>
1302 1304 *
1303 1305 * <p> If the {@code '('} or {@code ','} flags are given, then a {@link
1304 1306 * FormatFlagsConversionMismatchException} will be thrown.
1305 1307 *
1306 1308 * <tr><td valign="top"> {@code 'A'}
1307 1309 * <td valign="top"> <tt>'\u0041'</tt>
1308 1310 * <td> The upper-case variant of {@code 'a'}. The entire string
1309 1311 * representing the number will be converted to upper case including the
1310 1312 * {@code 'x'} (<tt>'\u0078'</tt>) and {@code 'p'}
1311 1313 * (<tt>'\u0070'</tt> and all hexadecimal digits {@code 'a'} -
1312 1314 * {@code 'f'} (<tt>'\u0061'</tt> - <tt>'\u0066'</tt>).
1313 1315 *
1314 1316 * </table>
1315 1317 *
1316 1318 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
1317 1319 * Long apply.
1318 1320 *
1319 1321 * <p> If the {@code '#'} flag is given, then the decimal separator will
1320 1322 * always be present.
1321 1323 *
1322 1324 * <p> If no <a name="floatdFlags">flags</a> are given the default formatting
1323 1325 * is as follows:
1324 1326 *
1325 1327 * <ul>
1326 1328 *
1327 1329 * <li> The output is right-justified within the {@code width}
1328 1330 *
1329 1331 * <li> Negative numbers begin with a {@code '-'}
1330 1332 *
1331 1333 * <li> Positive numbers and positive zero do not include a sign or extra
1332 1334 * leading space
1333 1335 *
1334 1336 * <li> No grouping separators are included
1335 1337 *
1336 1338 * <li> The decimal separator will only appear if a digit follows it
1337 1339 *
1338 1340 * </ul>
1339 1341 *
1340 1342 * <p> The <a name="floatDWidth">width</a> is the minimum number of characters
1341 1343 * to be written to the output. This includes any signs, digits, grouping
1342 1344 * separators, decimal separators, exponential symbol, radix indicator,
1343 1345 * parentheses, and strings representing infinity and NaN as applicable. If
1344 1346 * the length of the converted value is less than the width then the output
1345 1347 * will be padded by spaces (<tt>'\u0020'</tt>) until the total number of
1346 1348 * characters equals width. The padding is on the left by default. If the
1347 1349 * {@code '-'} flag is given then the padding will be on the right. If width
1348 1350 * is not specified then there is no minimum.
1349 1351 *
1350 1352 * <p> If the <a name="floatDPrec">conversion</a> is {@code 'e'},
1351 1353 * {@code 'E'} or {@code 'f'}, then the precision is the number of digits
1352 1354 * after the decimal separator. If the precision is not specified, then it is
1353 1355 * assumed to be {@code 6}.
1354 1356 *
1355 1357 * <p> If the conversion is {@code 'g'} or {@code 'G'}, then the precision is
1356 1358 * the total number of significant digits in the resulting magnitude after
1357 1359 * rounding. If the precision is not specified, then the default value is
1358 1360 * {@code 6}. If the precision is {@code 0}, then it is taken to be
1359 1361 * {@code 1}.
1360 1362 *
1361 1363 * <p> If the conversion is {@code 'a'} or {@code 'A'}, then the precision
1362 1364 * is the number of hexadecimal digits after the decimal separator. If the
1363 1365 * precision is not provided, then all of the digits as returned by {@link
1364 1366 * Double#toHexString(double)} will be output.
1365 1367 *
1366 1368 * <p><a name="dndec"><b> BigDecimal </b></a>
1367 1369 *
1368 1370 * <p> The following conversions may be applied {@link java.math.BigDecimal
1369 1371 * BigDecimal}.
1370 1372 *
1371 1373 * <table cellpadding=5 summary="floatConv">
1372 1374 *
1373 1375 * <tr><td valign="top"> {@code 'e'}
1374 1376 * <td valign="top"> <tt>'\u0065'</tt>
1375 1377 * <td> Requires the output to be formatted using <a
1376 1378 * name="scientific">computerized scientific notation</a>. The <a
1377 1379 * href="#l10n algorithm">localization algorithm</a> is applied.
1378 1380 *
1379 1381 * <p> The formatting of the magnitude <i>m</i> depends upon its value.
1380 1382 *
1381 1383 * <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
1382 1384 * will be {@code "+00"}.
1383 1385 *
1384 1386 * <p> Otherwise, the result is a string that represents the sign and
1385 1387 * magnitude (absolute value) of the argument. The formatting of the sign
1386 1388 * is described in the <a href="#l10n algorithm">localization
1387 1389 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
1388 1390 * value.
1389 1391 *
1390 1392 * <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
1391 1393 * <= <i>m</i> < 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
1392 1394 * mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
1393 1395 * that 1 <= <i>a</i> < 10. The magnitude is then represented as the
1394 1396 * integer part of <i>a</i>, as a single decimal digit, followed by the
1395 1397 * decimal separator followed by decimal digits representing the fractional
1396 1398 * part of <i>a</i>, followed by the exponent symbol {@code 'e'}
1397 1399 * (<tt>'\u0065'</tt>), followed by the sign of the exponent, followed
1398 1400 * by a representation of <i>n</i> as a decimal integer, as produced by the
1399 1401 * method {@link Long#toString(long, int)}, and zero-padded to include at
1400 1402 * least two digits.
1401 1403 *
1402 1404 * <p> The number of digits in the result for the fractional part of
1403 1405 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
1404 1406 * specified then the default value is {@code 6}. If the precision is
1405 1407 * less than the number of digits which would appear after the decimal
1406 1408 * point in the string returned by {@link Float#toString(float)} or {@link
1407 1409 * Double#toString(double)} respectively, then the value will be rounded
1408 1410 * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
1409 1411 * algorithm}. Otherwise, zeros may be appended to reach the precision.
1410 1412 * For a canonical representation of the value, use {@link
1411 1413 * BigDecimal#toString()}.
1412 1414 *
1413 1415 * <p> If the {@code ','} flag is given, then an {@link
1414 1416 * FormatFlagsConversionMismatchException} will be thrown.
1415 1417 *
1416 1418 * <tr><td valign="top"> {@code 'E'}
1417 1419 * <td valign="top"> <tt>'\u0045'</tt>
1418 1420 * <td> The upper-case variant of {@code 'e'}. The exponent symbol
1419 1421 * will be {@code 'E'} (<tt>'\u0045'</tt>).
1420 1422 *
1421 1423 * <tr><td valign="top"> {@code 'g'}
1422 1424 * <td valign="top"> <tt>'\u0067'</tt>
1423 1425 * <td> Requires the output to be formatted in general scientific notation
1424 1426 * as described below. The <a href="#l10n algorithm">localization
1425 1427 * algorithm</a> is applied.
1426 1428 *
1427 1429 * <p> After rounding for the precision, the formatting of the resulting
1428 1430 * magnitude <i>m</i> depends on its value.
1429 1431 *
1430 1432 * <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
1431 1433 * than 10<sup>precision</sup> then it is represented in <i><a
1432 1434 * href="#decimal">decimal format</a></i>.
1433 1435 *
1434 1436 * <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
1435 1437 * 10<sup>precision</sup>, then it is represented in <i><a
1436 1438 * href="#scientific">computerized scientific notation</a></i>.
1437 1439 *
1438 1440 * <p> The total number of significant digits in <i>m</i> is equal to the
1439 1441 * precision. If the precision is not specified, then the default value is
1440 1442 * {@code 6}. If the precision is {@code 0}, then it is taken to be
1441 1443 * {@code 1}.
1442 1444 *
1443 1445 * <p> If the {@code '#'} flag is given then an {@link
1444 1446 * FormatFlagsConversionMismatchException} will be thrown.
1445 1447 *
1446 1448 * <tr><td valign="top"> {@code 'G'}
1447 1449 * <td valign="top"> <tt>'\u0047'</tt>
1448 1450 * <td> The upper-case variant of {@code 'g'}.
1449 1451 *
1450 1452 * <tr><td valign="top"> {@code 'f'}
1451 1453 * <td valign="top"> <tt>'\u0066'</tt>
1452 1454 * <td> Requires the output to be formatted using <a name="decimal">decimal
1453 1455 * format</a>. The <a href="#l10n algorithm">localization algorithm</a> is
1454 1456 * applied.
1455 1457 *
1456 1458 * <p> The result is a string that represents the sign and magnitude
1457 1459 * (absolute value) of the argument. The formatting of the sign is
1458 1460 * described in the <a href="#l10n algorithm">localization
1459 1461 * algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
1460 1462 * value.
1461 1463 *
1462 1464 * <p> The magnitude is formatted as the integer part of <i>m</i>, with no
1463 1465 * leading zeroes, followed by the decimal separator followed by one or
1464 1466 * more decimal digits representing the fractional part of <i>m</i>.
1465 1467 *
1466 1468 * <p> The number of digits in the result for the fractional part of
1467 1469 * <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
1468 1470 * specified then the default value is {@code 6}. If the precision is
1469 1471 * less than the number of digits which would appear after the decimal
1470 1472 * point in the string returned by {@link Float#toString(float)} or {@link
1471 1473 * Double#toString(double)} respectively, then the value will be rounded
1472 1474 * using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
1473 1475 * algorithm}. Otherwise, zeros may be appended to reach the precision.
1474 1476 * For a canonical representation of the value, use {@link
1475 1477 * BigDecimal#toString()}.
1476 1478 *
1477 1479 * </table>
1478 1480 *
1479 1481 * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
1480 1482 * Long apply.
1481 1483 *
1482 1484 * <p> If the {@code '#'} flag is given, then the decimal separator will
1483 1485 * always be present.
1484 1486 *
1485 1487 * <p> The <a href="#floatdFlags">default behavior</a> when no flags are
1486 1488 * given is the same as for Float and Double.
1487 1489 *
1488 1490 * <p> The specification of <a href="#floatDWidth">width</a> and <a
1489 1491 * href="#floatDPrec">precision</a> is the same as defined for Float and
1490 1492 * Double.
1491 1493 *
1492 1494 * <h4><a name="ddt">Date/Time</a></h4>
1493 1495 *
1494 1496 * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
1495 1497 * Calendar}, and {@link Date}.
1496 1498 *
1497 1499 * <table cellpadding=5 summary="DTConv">
1498 1500 *
1499 1501 * <tr><td valign="top"> {@code 't'}
1500 1502 * <td valign="top"> <tt>'\u0074'</tt>
1501 1503 * <td> Prefix for date and time conversion characters.
1502 1504 * <tr><td valign="top"> {@code 'T'}
1503 1505 * <td valign="top"> <tt>'\u0054'</tt>
1504 1506 * <td> The upper-case variant of {@code 't'}.
1505 1507 *
1506 1508 * </table>
1507 1509 *
1508 1510 * <p> The following date and time conversion character suffixes are defined
1509 1511 * for the {@code 't'} and {@code 'T'} conversions. The types are similar to
1510 1512 * but not completely identical to those defined by GNU {@code date} and
1511 1513 * POSIX {@code strftime(3c)}. Additional conversion types are provided to
1512 1514 * access Java-specific functionality (e.g. {@code 'L'} for milliseconds
1513 1515 * within the second).
1514 1516 *
1515 1517 * <p> The following conversion characters are used for formatting times:
1516 1518 *
1517 1519 * <table cellpadding=5 summary="time">
1518 1520 *
1519 1521 * <tr><td valign="top"> {@code 'H'}
1520 1522 * <td valign="top"> <tt>'\u0048'</tt>
1521 1523 * <td> Hour of the day for the 24-hour clock, formatted as two digits with
1522 1524 * a leading zero as necessary i.e. {@code 00 - 23}. {@code 00}
1523 1525 * corresponds to midnight.
1524 1526 *
1525 1527 * <tr><td valign="top">{@code 'I'}
1526 1528 * <td valign="top"> <tt>'\u0049'</tt>
1527 1529 * <td> Hour for the 12-hour clock, formatted as two digits with a leading
1528 1530 * zero as necessary, i.e. {@code 01 - 12}. {@code 01} corresponds to
1529 1531 * one o'clock (either morning or afternoon).
1530 1532 *
1531 1533 * <tr><td valign="top">{@code 'k'}
1532 1534 * <td valign="top"> <tt>'\u006b'</tt>
1533 1535 * <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
1534 1536 * {@code 0} corresponds to midnight.
1535 1537 *
1536 1538 * <tr><td valign="top">{@code 'l'}
1537 1539 * <td valign="top"> <tt>'\u006c'</tt>
1538 1540 * <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}. {@code 1}
1539 1541 * corresponds to one o'clock (either morning or afternoon).
1540 1542 *
1541 1543 * <tr><td valign="top">{@code 'M'}
1542 1544 * <td valign="top"> <tt>'\u004d'</tt>
1543 1545 * <td> Minute within the hour formatted as two digits with a leading zero
1544 1546 * as necessary, i.e. {@code 00 - 59}.
1545 1547 *
1546 1548 * <tr><td valign="top">{@code 'S'}
1547 1549 * <td valign="top"> <tt>'\u0053'</tt>
1548 1550 * <td> Seconds within the minute, formatted as two digits with a leading
1549 1551 * zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
1550 1552 * value required to support leap seconds).
1551 1553 *
1552 1554 * <tr><td valign="top">{@code 'L'}
1553 1555 * <td valign="top"> <tt>'\u004c'</tt>
1554 1556 * <td> Millisecond within the second formatted as three digits with
1555 1557 * leading zeros as necessary, i.e. {@code 000 - 999}.
1556 1558 *
1557 1559 * <tr><td valign="top">{@code 'N'}
1558 1560 * <td valign="top"> <tt>'\u004e'</tt>
1559 1561 * <td> Nanosecond within the second, formatted as nine digits with leading
1560 1562 * zeros as necessary, i.e. {@code 000000000 - 999999999}. The precision
1561 1563 * of this value is limited by the resolution of the underlying operating
1562 1564 * system or hardware.
1563 1565 *
1564 1566 * <tr><td valign="top">{@code 'p'}
1565 1567 * <td valign="top"> <tt>'\u0070'</tt>
1566 1568 * <td> Locale-specific {@linkplain
1567 1569 * java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
1568 1570 * in lower case, e.g."{@code am}" or "{@code pm}". Use of the
1569 1571 * conversion prefix {@code 'T'} forces this output to upper case. (Note
1570 1572 * that {@code 'p'} produces lower-case output. This is different from
1571 1573 * GNU {@code date} and POSIX {@code strftime(3c)} which produce
1572 1574 * upper-case output.)
1573 1575 *
1574 1576 * <tr><td valign="top">{@code 'z'}
1575 1577 * <td valign="top"> <tt>'\u007a'</tt>
1576 1578 * <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>
1577 1579 * style numeric time zone offset from GMT, e.g. {@code -0800}. This
1578 1580 * value will be adjusted as necessary for Daylight Saving Time. For
1579 1581 * {@code long}, {@link Long}, and {@link Date} the time zone used is
1580 1582 * the {@linkplain TimeZone#getDefault() default time zone} for this
1581 1583 * instance of the Java virtual machine.
1582 1584 *
1583 1585 * <tr><td valign="top">{@code 'Z'}
1584 1586 * <td valign="top"> <tt>'\u005a'</tt>
1585 1587 * <td> A string representing the abbreviation for the time zone. This
1586 1588 * value will be adjusted as necessary for Daylight Saving Time. For
1587 1589 * {@code long}, {@link Long}, and {@link Date} the time zone used is
1588 1590 * the {@linkplain TimeZone#getDefault() default time zone} for this
1589 1591 * instance of the Java virtual machine. The Formatter's locale will
1590 1592 * supersede the locale of the argument (if any).
1591 1593 *
1592 1594 * <tr><td valign="top">{@code 's'}
1593 1595 * <td valign="top"> <tt>'\u0073'</tt>
1594 1596 * <td> Seconds since the beginning of the epoch starting at 1 January 1970
1595 1597 * {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
1596 1598 * {@code Long.MAX_VALUE/1000}.
1597 1599 *
1598 1600 * <tr><td valign="top">{@code 'Q'}
1599 1601 * <td valign="top"> <tt>'\u004f'</tt>
1600 1602 * <td> Milliseconds since the beginning of the epoch starting at 1 January
1601 1603 * 1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
1602 1604 * {@code Long.MAX_VALUE}. The precision of this value is limited by
1603 1605 * the resolution of the underlying operating system or hardware.
1604 1606 *
1605 1607 * </table>
1606 1608 *
1607 1609 * <p> The following conversion characters are used for formatting dates:
1608 1610 *
1609 1611 * <table cellpadding=5 summary="date">
1610 1612 *
1611 1613 * <tr><td valign="top">{@code 'B'}
1612 1614 * <td valign="top"> <tt>'\u0042'</tt>
1613 1615 * <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
1614 1616 * full month name}, e.g. {@code "January"}, {@code "February"}.
1615 1617 *
1616 1618 * <tr><td valign="top">{@code 'b'}
1617 1619 * <td valign="top"> <tt>'\u0062'</tt>
1618 1620 * <td> Locale-specific {@linkplain
1619 1621 * java.text.DateFormatSymbols#getShortMonths abbreviated month name},
1620 1622 * e.g. {@code "Jan"}, {@code "Feb"}.
1621 1623 *
1622 1624 * <tr><td valign="top">{@code 'h'}
1623 1625 * <td valign="top"> <tt>'\u0068'</tt>
1624 1626 * <td> Same as {@code 'b'}.
1625 1627 *
1626 1628 * <tr><td valign="top">{@code 'A'}
1627 1629 * <td valign="top"> <tt>'\u0041'</tt>
1628 1630 * <td> Locale-specific full name of the {@linkplain
1629 1631 * java.text.DateFormatSymbols#getWeekdays day of the week},
1630 1632 * e.g. {@code "Sunday"}, {@code "Monday"}
1631 1633 *
1632 1634 * <tr><td valign="top">{@code 'a'}
1633 1635 * <td valign="top"> <tt>'\u0061'</tt>
1634 1636 * <td> Locale-specific short name of the {@linkplain
1635 1637 * java.text.DateFormatSymbols#getShortWeekdays day of the week},
1636 1638 * e.g. {@code "Sun"}, {@code "Mon"}
1637 1639 *
1638 1640 * <tr><td valign="top">{@code 'C'}
1639 1641 * <td valign="top"> <tt>'\u0043'</tt>
1640 1642 * <td> Four-digit year divided by {@code 100}, formatted as two digits
1641 1643 * with leading zero as necessary, i.e. {@code 00 - 99}
1642 1644 *
1643 1645 * <tr><td valign="top">{@code 'Y'}
1644 1646 * <td valign="top"> <tt>'\u0059'</tt> <td> Year, formatted to at least
1645 1647 * four digits with leading zeros as necessary, e.g. {@code 0092} equals
1646 1648 * {@code 92} CE for the Gregorian calendar.
1647 1649 *
1648 1650 * <tr><td valign="top">{@code 'y'}
1649 1651 * <td valign="top"> <tt>'\u0079'</tt>
1650 1652 * <td> Last two digits of the year, formatted with leading zeros as
1651 1653 * necessary, i.e. {@code 00 - 99}.
1652 1654 *
1653 1655 * <tr><td valign="top">{@code 'j'}
1654 1656 * <td valign="top"> <tt>'\u006a'</tt>
1655 1657 * <td> Day of year, formatted as three digits with leading zeros as
1656 1658 * necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
1657 1659 * {@code 001} corresponds to the first day of the year.
1658 1660 *
1659 1661 * <tr><td valign="top">{@code 'm'}
1660 1662 * <td valign="top"> <tt>'\u006d'</tt>
1661 1663 * <td> Month, formatted as two digits with leading zeros as necessary,
1662 1664 * i.e. {@code 01 - 13}, where "{@code 01}" is the first month of the
1663 1665 * year and ("{@code 13}" is a special value required to support lunar
1664 1666 * calendars).
1665 1667 *
1666 1668 * <tr><td valign="top">{@code 'd'}
1667 1669 * <td valign="top"> <tt>'\u0064'</tt>
1668 1670 * <td> Day of month, formatted as two digits with leading zeros as
1669 1671 * necessary, i.e. {@code 01 - 31}, where "{@code 01}" is the first day
1670 1672 * of the month.
1671 1673 *
1672 1674 * <tr><td valign="top">{@code 'e'}
1673 1675 * <td valign="top"> <tt>'\u0065'</tt>
1674 1676 * <td> Day of month, formatted as two digits, i.e. {@code 1 - 31} where
1675 1677 * "{@code 1}" is the first day of the month.
1676 1678 *
1677 1679 * </table>
1678 1680 *
1679 1681 * <p> The following conversion characters are used for formatting common
1680 1682 * date/time compositions.
1681 1683 *
1682 1684 * <table cellpadding=5 summary="composites">
1683 1685 *
1684 1686 * <tr><td valign="top">{@code 'R'}
1685 1687 * <td valign="top"> <tt>'\u0052'</tt>
1686 1688 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
1687 1689 *
1688 1690 * <tr><td valign="top">{@code 'T'}
1689 1691 * <td valign="top"> <tt>'\u0054'</tt>
1690 1692 * <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
1691 1693 *
1692 1694 * <tr><td valign="top">{@code 'r'}
1693 1695 * <td valign="top"> <tt>'\u0072'</tt>
1694 1696 * <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS
1695 1697 * %Tp"}. The location of the morning or afternoon marker
1696 1698 * ({@code '%Tp'}) may be locale-dependent.
1697 1699 *
1698 1700 * <tr><td valign="top">{@code 'D'}
1699 1701 * <td valign="top"> <tt>'\u0044'</tt>
1700 1702 * <td> Date formatted as {@code "%tm/%td/%ty"}.
1701 1703 *
1702 1704 * <tr><td valign="top">{@code 'F'}
1703 1705 * <td valign="top"> <tt>'\u0046'</tt>
1704 1706 * <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a>
1705 1707 * complete date formatted as {@code "%tY-%tm-%td"}.
1706 1708 *
1707 1709 * <tr><td valign="top">{@code 'c'}
1708 1710 * <td valign="top"> <tt>'\u0063'</tt>
1709 1711 * <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
1710 1712 * e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
1711 1713 *
1712 1714 * </table>
1713 1715 *
1714 1716 * <p> The {@code '-'} flag defined for <a href="#dFlags">General
1715 1717 * conversions</a> applies. If the {@code '#'} flag is given, then a {@link
1716 1718 * FormatFlagsConversionMismatchException} will be thrown.
1717 1719 *
1718 1720 * <p> The <a name="dtWidth">width</a> is the minimum number of characters to
1719 1721 * be written to the output. If the length of the converted value is less than
1720 1722 * the {@code width} then the output will be padded by spaces
1721 1723 * (<tt>'\u0020'</tt>) until the total number of characters equals width.
1722 1724 * The padding is on the left by default. If the {@code '-'} flag is given
1723 1725 * then the padding will be on the right. If width is not specified then there
1724 1726 * is no minimum.
1725 1727 *
1726 1728 * <p> The precision is not applicable. If the precision is specified then an
1727 1729 * {@link IllegalFormatPrecisionException} will be thrown.
1728 1730 *
1729 1731 * <h4><a name="dper">Percent</a></h4>
1730 1732 *
1731 1733 * <p> The conversion does not correspond to any argument.
1732 1734 *
1733 1735 * <table cellpadding=5 summary="DTConv">
1734 1736 *
1735 1737 * <tr><td valign="top">{@code '%'}
1736 1738 * <td> The result is a literal {@code '%'} (<tt>'\u0025'</tt>)
1737 1739 *
1738 1740 * <p> The <a name="dtWidth">width</a> is the minimum number of characters to
1739 1741 * be written to the output including the {@code '%'}. If the length of the
1740 1742 * converted value is less than the {@code width} then the output will be
1741 1743 * padded by spaces (<tt>'\u0020'</tt>) until the total number of
1742 1744 * characters equals width. The padding is on the left. If width is not
1743 1745 * specified then just the {@code '%'} is output.
1744 1746 *
1745 1747 * <p> The {@code '-'} flag defined for <a href="#dFlags">General
1746 1748 * conversions</a> applies. If any other flags are provided, then a
1747 1749 * {@link FormatFlagsConversionMismatchException} will be thrown.
1748 1750 *
1749 1751 * <p> The precision is not applicable. If the precision is specified an
1750 1752 * {@link IllegalFormatPrecisionException} will be thrown.
1751 1753 *
1752 1754 * </table>
1753 1755 *
1754 1756 * <h4><a name="dls">Line Separator</a></h4>
1755 1757 *
1756 1758 * <p> The conversion does not correspond to any argument.
1757 1759 *
1758 1760 * <table cellpadding=5 summary="DTConv">
1759 1761 *
1760 1762 * <tr><td valign="top">{@code 'n'}
1761 1763 * <td> the platform-specific line separator as returned by {@link
1762 1764 * System#getProperty System.getProperty("line.separator")}.
1763 1765 *
1764 1766 * </table>
1765 1767 *
1766 1768 * <p> Flags, width, and precision are not applicable. If any are provided an
1767 1769 * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException},
1768 1770 * and {@link IllegalFormatPrecisionException}, respectively will be thrown.
1769 1771 *
1770 1772 * <h4><a name="dpos">Argument Index</a></h4>
1771 1773 *
1772 1774 * <p> Format specifiers can reference arguments in three ways:
1773 1775 *
1774 1776 * <ul>
1775 1777 *
1776 1778 * <li> <i>Explicit indexing</i> is used when the format specifier contains an
1777 1779 * argument index. The argument index is a decimal integer indicating the
1778 1780 * position of the argument in the argument list. The first argument is
1779 1781 * referenced by "{@code 1$}", the second by "{@code 2$}", etc. An argument
1780 1782 * may be referenced more than once.
1781 1783 *
1782 1784 * <p> For example:
1783 1785 *
1784 1786 * <blockquote><pre>
1785 1787 * formatter.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s",
1786 1788 * "a", "b", "c", "d")
1787 1789 * // -> "d c b a d c b a"
1788 1790 * </pre></blockquote>
1789 1791 *
1790 1792 * <li> <i>Relative indexing</i> is used when the format specifier contains a
1791 1793 * {@code '<'} (<tt>'\u003c'</tt>) flag which causes the argument for
1792 1794 * the previous format specifier to be re-used. If there is no previous
1793 1795 * argument, then a {@link MissingFormatArgumentException} is thrown.
1794 1796 *
1795 1797 * <blockquote><pre>
1796 1798 * formatter.format("%s %s %<s %<s", "a", "b", "c", "d")
1797 1799 * // -> "a b b b"
1798 1800 * // "c" and "d" are ignored because they are not referenced
1799 1801 * </pre></blockquote>
1800 1802 *
1801 1803 * <li> <i>Ordinary indexing</i> is used when the format specifier contains
1802 1804 * neither an argument index nor a {@code '<'} flag. Each format specifier
1803 1805 * which uses ordinary indexing is assigned a sequential implicit index into
1804 1806 * argument list which is independent of the indices used by explicit or
1805 1807 * relative indexing.
1806 1808 *
1807 1809 * <blockquote><pre>
1808 1810 * formatter.format("%s %s %s %s", "a", "b", "c", "d")
1809 1811 * // -> "a b c d"
1810 1812 * </pre></blockquote>
1811 1813 *
1812 1814 * </ul>
1813 1815 *
1814 1816 * <p> It is possible to have a format string which uses all forms of indexing,
1815 1817 * for example:
1816 1818 *
1817 1819 * <blockquote><pre>
1818 1820 * formatter.format("%2$s %s %<s %s", "a", "b", "c", "d")
1819 1821 * // -> "b a a b"
1820 1822 * // "c" and "d" are ignored because they are not referenced
1821 1823 * </pre></blockquote>
1822 1824 *
1823 1825 * <p> The maximum number of arguments is limited by the maximum dimension of a
1824 1826 * Java array as defined by the <a
1825 1827 * href="http://java.sun.com/docs/books/vmspec/">Java Virtual Machine
1826 1828 * Specification</a>. If the argument index is does not correspond to an
1827 1829 * available argument, then a {@link MissingFormatArgumentException} is thrown.
1828 1830 *
1829 1831 * <p> If there are more arguments than format specifiers, the extra arguments
1830 1832 * are ignored.
↓ open down ↓ |
1768 lines elided |
↑ open up ↑ |
1831 1833 *
1832 1834 * <p> Unless otherwise specified, passing a {@code null} argument to any
1833 1835 * method or constructor in this class will cause a {@link
1834 1836 * NullPointerException} to be thrown.
1835 1837 *
1836 1838 * @author Iris Clark
1837 1839 * @since 1.5
1838 1840 */
1839 1841 public final class Formatter implements Closeable, Flushable {
1840 1842 private Appendable a;
1841 - private Locale l;
1843 + private final Locale l;
1842 1844
1843 1845 private IOException lastException;
1844 1846
1845 - private char zero = '0';
1847 + private final char zero;
1846 1848 private static double scaleUp;
1847 1849
1848 1850 // 1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
1849 1851 // + 3 (max # exp digits) + 4 (error) = 30
1850 1852 private static final int MAX_FD_CHARS = 30;
1851 1853
1852 - // Initialize internal data.
1853 - private void init(Appendable a, Locale l) {
1854 + /**
1855 + * Verifies that the given charset is supported.
1856 + * @throws NullPointerException is csn is null
1857 + * @throws UnsupportedEncodingException if the charset is not supported
1858 + */
1859 + private static Void verifyCharsetName(String csn)
1860 + throws UnsupportedEncodingException {
1861 + Objects.nonNull(csn, "charsetName");
1862 + try {
1863 + if (Charset.isSupported(csn))
1864 + return null;
1865 + } catch (IllegalCharsetNameException unused) {
1866 + /* swallow this exception since UnsupportedEncodingException
1867 + * will be thrown */
1868 + }
1869 + throw new UnsupportedEncodingException(csn);
1870 + }
1871 +
1872 + private static final Appendable nonNullAppendable(Appendable a) {
1873 + if (a == null)
1874 + return new StringBuilder();
1875 +
1876 + return a;
1877 + }
1878 +
1879 + // Private constructors
1880 + private Formatter(Void unused, Locale l, Appendable a) {
1881 + this(l, a);
1882 + }
1883 +
1884 + private Formatter(Locale l, Appendable a) {
1854 1885 this.a = a;
1855 1886 this.l = l;
1856 - setZero();
1887 + this.zero = getZero(l);
1857 1888 }
1858 1889
1859 1890 /**
1860 1891 * Constructs a new formatter.
1861 1892 *
1862 1893 * <p> The destination of the formatted output is a {@link StringBuilder}
1863 1894 * which may be retrieved by invoking {@link #out out()} and whose
1864 1895 * current content may be converted into a string by invoking {@link
1865 1896 * #toString toString()}. The locale used is the {@linkplain
1866 1897 * Locale#getDefault() default locale} for this instance of the Java
1867 1898 * virtual machine.
1868 1899 */
1869 1900 public Formatter() {
1870 - init(new StringBuilder(), Locale.getDefault(Locale.Category.FORMAT));
1901 + this(Locale.getDefault(Locale.Category.FORMAT), new StringBuilder());
1871 1902 }
1872 1903
1873 1904 /**
1874 1905 * Constructs a new formatter with the specified destination.
1875 1906 *
1876 1907 * <p> The locale used is the {@linkplain Locale#getDefault() default
1877 1908 * locale} for this instance of the Java virtual machine.
1878 1909 *
1879 1910 * @param a
1880 1911 * Destination for the formatted output. If {@code a} is
1881 1912 * {@code null} then a {@link StringBuilder} will be created.
1882 1913 */
1883 1914 public Formatter(Appendable a) {
1884 - if (a == null)
1885 - a = new StringBuilder();
1886 - init(a, Locale.getDefault(Locale.Category.FORMAT));
1915 + this(Locale.getDefault(Locale.Category.FORMAT), nonNullAppendable(a));
1887 1916 }
1888 1917
1889 1918 /**
1890 1919 * Constructs a new formatter with the specified locale.
1891 1920 *
1892 1921 * <p> The destination of the formatted output is a {@link StringBuilder}
1893 1922 * which may be retrieved by invoking {@link #out out()} and whose current
1894 1923 * content may be converted into a string by invoking {@link #toString
1895 1924 * toString()}.
1896 1925 *
1897 1926 * @param l
1898 1927 * The {@linkplain java.util.Locale locale} to apply during
1899 1928 * formatting. If {@code l} is {@code null} then no localization
1900 1929 * is applied.
1901 1930 */
1902 1931 public Formatter(Locale l) {
1903 - init(new StringBuilder(), l);
1932 + this(l, new StringBuilder());
1904 1933 }
1905 1934
1906 1935 /**
1907 1936 * Constructs a new formatter with the specified destination and locale.
1908 1937 *
1909 1938 * @param a
1910 1939 * Destination for the formatted output. If {@code a} is
1911 1940 * {@code null} then a {@link StringBuilder} will be created.
1912 1941 *
1913 1942 * @param l
1914 1943 * The {@linkplain java.util.Locale locale} to apply during
1915 1944 * formatting. If {@code l} is {@code null} then no localization
1916 1945 * is applied.
1917 1946 */
1918 1947 public Formatter(Appendable a, Locale l) {
1919 - if (a == null)
1920 - a = new StringBuilder();
1921 - init(a, l);
1948 + this(l, nonNullAppendable(a));
1922 1949 }
1923 1950
1924 1951 /**
1925 1952 * Constructs a new formatter with the specified file name.
1926 1953 *
1927 1954 * <p> The charset used is the {@linkplain
1928 1955 * java.nio.charset.Charset#defaultCharset() default charset} for this
1929 1956 * instance of the Java virtual machine.
1930 1957 *
1931 1958 * <p> The locale used is the {@linkplain Locale#getDefault() default
1932 1959 * locale} for this instance of the Java virtual machine.
1933 1960 *
1934 1961 * @param fileName
1935 1962 * The name of the file to use as the destination of this
1936 1963 * formatter. If the file exists then it will be truncated to
1937 1964 * zero size; otherwise, a new file will be created. The output
1938 1965 * will be written to the file and is buffered.
1939 1966 *
1940 1967 * @throws SecurityException
1941 1968 * If a security manager is present and {@link
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
1942 1969 * SecurityManager#checkWrite checkWrite(fileName)} denies write
1943 1970 * access to the file
1944 1971 *
1945 1972 * @throws FileNotFoundException
1946 1973 * If the given file name does not denote an existing, writable
1947 1974 * regular file and a new regular file of that name cannot be
1948 1975 * created, or if some other error occurs while opening or
1949 1976 * creating the file
1950 1977 */
1951 1978 public Formatter(String fileName) throws FileNotFoundException {
1952 - init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
1953 - Locale.getDefault(Locale.Category.FORMAT));
1979 + this(Locale.getDefault(Locale.Category.FORMAT),
1980 + new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))));
1954 1981 }
1955 1982
1956 1983 /**
1957 1984 * Constructs a new formatter with the specified file name and charset.
1958 1985 *
1959 1986 * <p> The locale used is the {@linkplain Locale#getDefault default
1960 1987 * locale} for this instance of the Java virtual machine.
1961 1988 *
1962 1989 * @param fileName
1963 1990 * The name of the file to use as the destination of this
1964 1991 * formatter. If the file exists then it will be truncated to
1965 1992 * zero size; otherwise, a new file will be created. The output
1966 1993 * will be written to the file and is buffered.
1967 1994 *
1968 1995 * @param csn
1969 1996 * The name of a supported {@linkplain java.nio.charset.Charset
1970 1997 * charset}
1971 1998 *
1972 1999 * @throws FileNotFoundException
1973 2000 * If the given file name does not denote an existing, writable
1974 2001 * regular file and a new regular file of that name cannot be
1975 2002 * created, or if some other error occurs while opening or
1976 2003 * creating the file
1977 2004 *
1978 2005 * @throws SecurityException
1979 2006 * If a security manager is present and {@link
1980 2007 * SecurityManager#checkWrite checkWrite(fileName)} denies write
1981 2008 * access to the file
1982 2009 *
1983 2010 * @throws UnsupportedEncodingException
1984 2011 * If the named charset is not supported
1985 2012 */
1986 2013 public Formatter(String fileName, String csn)
1987 2014 throws FileNotFoundException, UnsupportedEncodingException
1988 2015 {
1989 2016 this(fileName, csn, Locale.getDefault(Locale.Category.FORMAT));
1990 2017 }
1991 2018
1992 2019 /**
1993 2020 * Constructs a new formatter with the specified file name, charset, and
1994 2021 * locale.
1995 2022 *
1996 2023 * @param fileName
1997 2024 * The name of the file to use as the destination of this
1998 2025 * formatter. If the file exists then it will be truncated to
1999 2026 * zero size; otherwise, a new file will be created. The output
2000 2027 * will be written to the file and is buffered.
2001 2028 *
2002 2029 * @param csn
2003 2030 * The name of a supported {@linkplain java.nio.charset.Charset
2004 2031 * charset}
2005 2032 *
2006 2033 * @param l
2007 2034 * The {@linkplain java.util.Locale locale} to apply during
2008 2035 * formatting. If {@code l} is {@code null} then no localization
2009 2036 * is applied.
2010 2037 *
2011 2038 * @throws FileNotFoundException
2012 2039 * If the given file name does not denote an existing, writable
2013 2040 * regular file and a new regular file of that name cannot be
2014 2041 * created, or if some other error occurs while opening or
2015 2042 * creating the file
2016 2043 *
2017 2044 * @throws SecurityException
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
2018 2045 * If a security manager is present and {@link
2019 2046 * SecurityManager#checkWrite checkWrite(fileName)} denies write
2020 2047 * access to the file
2021 2048 *
2022 2049 * @throws UnsupportedEncodingException
2023 2050 * If the named charset is not supported
2024 2051 */
2025 2052 public Formatter(String fileName, String csn, Locale l)
2026 2053 throws FileNotFoundException, UnsupportedEncodingException
2027 2054 {
2028 - init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), csn)),
2029 - l);
2055 + this(verifyCharsetName(csn),
2056 + l,
2057 + new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), csn)));
2030 2058 }
2031 2059
2032 2060 /**
2033 2061 * Constructs a new formatter with the specified file.
2034 2062 *
2035 2063 * <p> The charset used is the {@linkplain
2036 2064 * java.nio.charset.Charset#defaultCharset() default charset} for this
2037 2065 * instance of the Java virtual machine.
2038 2066 *
2039 2067 * <p> The locale used is the {@linkplain Locale#getDefault() default
2040 2068 * locale} for this instance of the Java virtual machine.
2041 2069 *
2042 2070 * @param file
2043 2071 * The file to use as the destination of this formatter. If the
2044 2072 * file exists then it will be truncated to zero size; otherwise,
2045 2073 * a new file will be created. The output will be written to the
2046 2074 * file and is buffered.
2047 2075 *
2048 2076 * @throws SecurityException
2049 2077 * If a security manager is present and {@link
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
2050 2078 * SecurityManager#checkWrite checkWrite(file.getPath())} denies
2051 2079 * write access to the file
2052 2080 *
2053 2081 * @throws FileNotFoundException
2054 2082 * If the given file object does not denote an existing, writable
2055 2083 * regular file and a new regular file of that name cannot be
2056 2084 * created, or if some other error occurs while opening or
2057 2085 * creating the file
2058 2086 */
2059 2087 public Formatter(File file) throws FileNotFoundException {
2060 - init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
2061 - Locale.getDefault(Locale.Category.FORMAT));
2088 + this(Locale.getDefault(Locale.Category.FORMAT),
2089 + new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))));
2062 2090 }
2063 2091
2064 2092 /**
2065 2093 * Constructs a new formatter with the specified file and charset.
2066 2094 *
2067 2095 * <p> The locale used is the {@linkplain Locale#getDefault default
2068 2096 * locale} for this instance of the Java virtual machine.
2069 2097 *
2070 2098 * @param file
2071 2099 * The file to use as the destination of this formatter. If the
2072 2100 * file exists then it will be truncated to zero size; otherwise,
2073 2101 * a new file will be created. The output will be written to the
2074 2102 * file and is buffered.
2075 2103 *
2076 2104 * @param csn
2077 2105 * The name of a supported {@linkplain java.nio.charset.Charset
2078 2106 * charset}
2079 2107 *
2080 2108 * @throws FileNotFoundException
2081 2109 * If the given file object does not denote an existing, writable
2082 2110 * regular file and a new regular file of that name cannot be
2083 2111 * created, or if some other error occurs while opening or
2084 2112 * creating the file
2085 2113 *
2086 2114 * @throws SecurityException
2087 2115 * If a security manager is present and {@link
2088 2116 * SecurityManager#checkWrite checkWrite(file.getPath())} denies
2089 2117 * write access to the file
2090 2118 *
2091 2119 * @throws UnsupportedEncodingException
2092 2120 * If the named charset is not supported
2093 2121 */
2094 2122 public Formatter(File file, String csn)
2095 2123 throws FileNotFoundException, UnsupportedEncodingException
2096 2124 {
2097 2125 this(file, csn, Locale.getDefault(Locale.Category.FORMAT));
2098 2126 }
2099 2127
2100 2128 /**
2101 2129 * Constructs a new formatter with the specified file, charset, and
2102 2130 * locale.
2103 2131 *
2104 2132 * @param file
2105 2133 * The file to use as the destination of this formatter. If the
2106 2134 * file exists then it will be truncated to zero size; otherwise,
2107 2135 * a new file will be created. The output will be written to the
2108 2136 * file and is buffered.
2109 2137 *
2110 2138 * @param csn
2111 2139 * The name of a supported {@linkplain java.nio.charset.Charset
2112 2140 * charset}
2113 2141 *
2114 2142 * @param l
2115 2143 * The {@linkplain java.util.Locale locale} to apply during
2116 2144 * formatting. If {@code l} is {@code null} then no localization
2117 2145 * is applied.
2118 2146 *
2119 2147 * @throws FileNotFoundException
2120 2148 * If the given file object does not denote an existing, writable
2121 2149 * regular file and a new regular file of that name cannot be
2122 2150 * created, or if some other error occurs while opening or
2123 2151 * creating the file
2124 2152 *
2125 2153 * @throws SecurityException
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
2126 2154 * If a security manager is present and {@link
2127 2155 * SecurityManager#checkWrite checkWrite(file.getPath())} denies
2128 2156 * write access to the file
2129 2157 *
2130 2158 * @throws UnsupportedEncodingException
2131 2159 * If the named charset is not supported
2132 2160 */
2133 2161 public Formatter(File file, String csn, Locale l)
2134 2162 throws FileNotFoundException, UnsupportedEncodingException
2135 2163 {
2136 - init(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), csn)),
2137 - l);
2164 + this(verifyCharsetName(csn),
2165 + l,
2166 + new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), csn)));
2138 2167 }
2139 2168
2140 2169 /**
2141 2170 * Constructs a new formatter with the specified print stream.
2142 2171 *
2143 2172 * <p> The locale used is the {@linkplain Locale#getDefault() default
2144 2173 * locale} for this instance of the Java virtual machine.
2145 2174 *
2146 2175 * <p> Characters are written to the given {@link java.io.PrintStream
2147 2176 * PrintStream} object and are therefore encoded using that object's
2148 2177 * charset.
2149 2178 *
2150 2179 * @param ps
2151 2180 * The stream to use as the destination of this formatter.
2152 2181 */
2153 2182 public Formatter(PrintStream ps) {
2154 - if (ps == null)
2155 - throw new NullPointerException();
2156 - init((Appendable)ps, Locale.getDefault(Locale.Category.FORMAT));
2183 + this(Locale.getDefault(Locale.Category.FORMAT),
2184 + (Appendable)Objects.nonNull(ps));
2157 2185 }
2158 2186
2159 2187 /**
2160 2188 * Constructs a new formatter with the specified output stream.
2161 2189 *
2162 2190 * <p> The charset used is the {@linkplain
2163 2191 * java.nio.charset.Charset#defaultCharset() default charset} for this
2164 2192 * instance of the Java virtual machine.
2165 2193 *
2166 2194 * <p> The locale used is the {@linkplain Locale#getDefault() default
2167 2195 * locale} for this instance of the Java virtual machine.
2168 2196 *
2169 2197 * @param os
2170 2198 * The output stream to use as the destination of this formatter.
2171 2199 * The output will be buffered.
2172 2200 */
2173 2201 public Formatter(OutputStream os) {
2174 - init(new BufferedWriter(new OutputStreamWriter(os)),
2175 - Locale.getDefault(Locale.Category.FORMAT));
2202 + this(Locale.getDefault(Locale.Category.FORMAT),
2203 + new BufferedWriter(new OutputStreamWriter(os)));
2176 2204 }
2177 2205
2178 2206 /**
2179 2207 * Constructs a new formatter with the specified output stream and
2180 2208 * charset.
2181 2209 *
2182 2210 * <p> The locale used is the {@linkplain Locale#getDefault default
2183 2211 * locale} for this instance of the Java virtual machine.
2184 2212 *
2185 2213 * @param os
2186 2214 * The output stream to use as the destination of this formatter.
2187 2215 * The output will be buffered.
2188 2216 *
2189 2217 * @param csn
2190 2218 * The name of a supported {@linkplain java.nio.charset.Charset
2191 2219 * charset}
2192 2220 *
2193 2221 * @throws UnsupportedEncodingException
2194 2222 * If the named charset is not supported
2195 2223 */
2196 2224 public Formatter(OutputStream os, String csn)
2197 2225 throws UnsupportedEncodingException
2198 2226 {
2199 2227 this(os, csn, Locale.getDefault(Locale.Category.FORMAT));
2200 2228 }
2201 2229
2202 2230 /**
2203 2231 * Constructs a new formatter with the specified output stream, charset,
2204 2232 * and locale.
2205 2233 *
2206 2234 * @param os
2207 2235 * The output stream to use as the destination of this formatter.
2208 2236 * The output will be buffered.
2209 2237 *
2210 2238 * @param csn
2211 2239 * The name of a supported {@linkplain java.nio.charset.Charset
2212 2240 * charset}
2213 2241 *
2214 2242 * @param l
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
2215 2243 * The {@linkplain java.util.Locale locale} to apply during
2216 2244 * formatting. If {@code l} is {@code null} then no localization
2217 2245 * is applied.
2218 2246 *
2219 2247 * @throws UnsupportedEncodingException
2220 2248 * If the named charset is not supported
2221 2249 */
2222 2250 public Formatter(OutputStream os, String csn, Locale l)
2223 2251 throws UnsupportedEncodingException
2224 2252 {
2225 - init(new BufferedWriter(new OutputStreamWriter(os, csn)), l);
2253 + this(l, new BufferedWriter(new OutputStreamWriter(os, csn)));
2226 2254 }
2227 2255
2228 - private void setZero() {
2256 + private static final char getZero(Locale l) {
2229 2257 if ((l != null) && !l.equals(Locale.US)) {
2230 2258 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
2231 - zero = dfs.getZeroDigit();
2259 + return dfs.getZeroDigit();
2260 + } else {
2261 + return '0';
2232 2262 }
2233 2263 }
2234 2264
2235 2265 /**
2236 2266 * Returns the locale set by the construction of this formatter.
2237 2267 *
2238 2268 * <p> The {@link #format(java.util.Locale,String,Object...) format} method
2239 2269 * for this object which has a locale argument does not change this value.
2240 2270 *
2241 2271 * @return {@code null} if no localization is applied, otherwise a
2242 2272 * locale
2243 2273 *
2244 2274 * @throws FormatterClosedException
2245 2275 * If this formatter has been closed by invoking its {@link
2246 2276 * #close()} method
2247 2277 */
2248 2278 public Locale locale() {
2249 2279 ensureOpen();
2250 2280 return l;
2251 2281 }
2252 2282
2253 2283 /**
2254 2284 * Returns the destination for the output.
2255 2285 *
2256 2286 * @return The destination for the output
2257 2287 *
2258 2288 * @throws FormatterClosedException
2259 2289 * If this formatter has been closed by invoking its {@link
2260 2290 * #close()} method
2261 2291 */
2262 2292 public Appendable out() {
2263 2293 ensureOpen();
2264 2294 return a;
2265 2295 }
2266 2296
2267 2297 /**
2268 2298 * Returns the result of invoking {@code toString()} on the destination
2269 2299 * for the output. For example, the following code formats text into a
2270 2300 * {@link StringBuilder} then retrieves the resultant string:
2271 2301 *
2272 2302 * <blockquote><pre>
2273 2303 * Formatter f = new Formatter();
2274 2304 * f.format("Last reboot at %tc", lastRebootDate);
2275 2305 * String s = f.toString();
2276 2306 * // -> s == "Last reboot at Sat Jan 01 00:00:00 PST 2000"
2277 2307 * </pre></blockquote>
2278 2308 *
2279 2309 * <p> An invocation of this method behaves in exactly the same way as the
2280 2310 * invocation
2281 2311 *
2282 2312 * <pre>
2283 2313 * out().toString() </pre>
2284 2314 *
2285 2315 * <p> Depending on the specification of {@code toString} for the {@link
2286 2316 * Appendable}, the returned string may or may not contain the characters
2287 2317 * written to the destination. For instance, buffers typically return
2288 2318 * their contents in {@code toString()}, but streams cannot since the
2289 2319 * data is discarded.
2290 2320 *
2291 2321 * @return The result of invoking {@code toString()} on the destination
2292 2322 * for the output
2293 2323 *
2294 2324 * @throws FormatterClosedException
2295 2325 * If this formatter has been closed by invoking its {@link
2296 2326 * #close()} method
2297 2327 */
2298 2328 public String toString() {
2299 2329 ensureOpen();
2300 2330 return a.toString();
2301 2331 }
2302 2332
2303 2333 /**
2304 2334 * Flushes this formatter. If the destination implements the {@link
2305 2335 * java.io.Flushable} interface, its {@code flush} method will be invoked.
2306 2336 *
2307 2337 * <p> Flushing a formatter writes any buffered output in the destination
2308 2338 * to the underlying stream.
2309 2339 *
2310 2340 * @throws FormatterClosedException
2311 2341 * If this formatter has been closed by invoking its {@link
2312 2342 * #close()} method
2313 2343 */
2314 2344 public void flush() {
2315 2345 ensureOpen();
2316 2346 if (a instanceof Flushable) {
2317 2347 try {
2318 2348 ((Flushable)a).flush();
2319 2349 } catch (IOException ioe) {
2320 2350 lastException = ioe;
2321 2351 }
2322 2352 }
2323 2353 }
2324 2354
2325 2355 /**
2326 2356 * Closes this formatter. If the destination implements the {@link
2327 2357 * java.io.Closeable} interface, its {@code close} method will be invoked.
2328 2358 *
2329 2359 * <p> Closing a formatter allows it to release resources it may be holding
2330 2360 * (such as open files). If the formatter is already closed, then invoking
2331 2361 * this method has no effect.
2332 2362 *
2333 2363 * <p> Attempting to invoke any methods except {@link #ioException()} in
2334 2364 * this formatter after it has been closed will result in a {@link
2335 2365 * FormatterClosedException}.
2336 2366 */
2337 2367 public void close() {
2338 2368 if (a == null)
2339 2369 return;
2340 2370 try {
2341 2371 if (a instanceof Closeable)
2342 2372 ((Closeable)a).close();
2343 2373 } catch (IOException ioe) {
2344 2374 lastException = ioe;
2345 2375 } finally {
2346 2376 a = null;
2347 2377 }
2348 2378 }
2349 2379
2350 2380 private void ensureOpen() {
2351 2381 if (a == null)
2352 2382 throw new FormatterClosedException();
2353 2383 }
2354 2384
2355 2385 /**
2356 2386 * Returns the {@code IOException} last thrown by this formatter's {@link
2357 2387 * Appendable}.
2358 2388 *
2359 2389 * <p> If the destination's {@code append()} method never throws
2360 2390 * {@code IOException}, then this method will always return {@code null}.
2361 2391 *
2362 2392 * @return The last exception thrown by the Appendable or {@code null} if
2363 2393 * no such exception exists.
2364 2394 */
2365 2395 public IOException ioException() {
2366 2396 return lastException;
2367 2397 }
2368 2398
2369 2399 /**
2370 2400 * Writes a formatted string to this object's destination using the
2371 2401 * specified format string and arguments. The locale used is the one
2372 2402 * defined during the construction of this formatter.
2373 2403 *
2374 2404 * @param format
2375 2405 * A format string as described in <a href="#syntax">Format string
2376 2406 * syntax</a>.
2377 2407 *
2378 2408 * @param args
2379 2409 * Arguments referenced by the format specifiers in the format
2380 2410 * string. If there are more arguments than format specifiers, the
2381 2411 * extra arguments are ignored. The maximum number of arguments is
2382 2412 * limited by the maximum dimension of a Java array as defined by
2383 2413 * the <a href="http://java.sun.com/docs/books/vmspec/">Java
2384 2414 * Virtual Machine Specification</a>.
2385 2415 *
2386 2416 * @throws IllegalFormatException
2387 2417 * If a format string contains an illegal syntax, a format
2388 2418 * specifier that is incompatible with the given arguments,
2389 2419 * insufficient arguments given the format string, or other
2390 2420 * illegal conditions. For specification of all possible
2391 2421 * formatting errors, see the <a href="#detail">Details</a>
2392 2422 * section of the formatter class specification.
2393 2423 *
2394 2424 * @throws FormatterClosedException
2395 2425 * If this formatter has been closed by invoking its {@link
2396 2426 * #close()} method
2397 2427 *
2398 2428 * @return This formatter
2399 2429 */
2400 2430 public Formatter format(String format, Object ... args) {
2401 2431 return format(l, format, args);
2402 2432 }
2403 2433
2404 2434 /**
2405 2435 * Writes a formatted string to this object's destination using the
2406 2436 * specified locale, format string, and arguments.
2407 2437 *
2408 2438 * @param l
2409 2439 * The {@linkplain java.util.Locale locale} to apply during
2410 2440 * formatting. If {@code l} is {@code null} then no localization
2411 2441 * is applied. This does not change this object's locale that was
2412 2442 * set during construction.
2413 2443 *
2414 2444 * @param format
2415 2445 * A format string as described in <a href="#syntax">Format string
2416 2446 * syntax</a>
2417 2447 *
2418 2448 * @param args
2419 2449 * Arguments referenced by the format specifiers in the format
2420 2450 * string. If there are more arguments than format specifiers, the
2421 2451 * extra arguments are ignored. The maximum number of arguments is
2422 2452 * limited by the maximum dimension of a Java array as defined by
2423 2453 * the <a href="http://java.sun.com/docs/books/vmspec/">Java
2424 2454 * Virtual Machine Specification</a>
2425 2455 *
2426 2456 * @throws IllegalFormatException
2427 2457 * If a format string contains an illegal syntax, a format
2428 2458 * specifier that is incompatible with the given arguments,
2429 2459 * insufficient arguments given the format string, or other
2430 2460 * illegal conditions. For specification of all possible
2431 2461 * formatting errors, see the <a href="#detail">Details</a>
2432 2462 * section of the formatter class specification.
2433 2463 *
2434 2464 * @throws FormatterClosedException
2435 2465 * If this formatter has been closed by invoking its {@link
2436 2466 * #close()} method
2437 2467 *
2438 2468 * @return This formatter
2439 2469 */
2440 2470 public Formatter format(Locale l, String format, Object ... args) {
2441 2471 ensureOpen();
2442 2472
2443 2473 // index of last argument referenced
2444 2474 int last = -1;
2445 2475 // last ordinary index
2446 2476 int lasto = -1;
2447 2477
2448 2478 FormatString[] fsa = parse(format);
2449 2479 for (int i = 0; i < fsa.length; i++) {
2450 2480 FormatString fs = fsa[i];
2451 2481 int index = fs.index();
2452 2482 try {
2453 2483 switch (index) {
2454 2484 case -2: // fixed string, "%n", or "%%"
2455 2485 fs.print(null, l);
2456 2486 break;
2457 2487 case -1: // relative index
2458 2488 if (last < 0 || (args != null && last > args.length - 1))
2459 2489 throw new MissingFormatArgumentException(fs.toString());
2460 2490 fs.print((args == null ? null : args[last]), l);
2461 2491 break;
2462 2492 case 0: // ordinary index
2463 2493 lasto++;
2464 2494 last = lasto;
2465 2495 if (args != null && lasto > args.length - 1)
2466 2496 throw new MissingFormatArgumentException(fs.toString());
2467 2497 fs.print((args == null ? null : args[lasto]), l);
2468 2498 break;
2469 2499 default: // explicit index
2470 2500 last = index - 1;
2471 2501 if (args != null && last > args.length - 1)
2472 2502 throw new MissingFormatArgumentException(fs.toString());
2473 2503 fs.print((args == null ? null : args[last]), l);
2474 2504 break;
2475 2505 }
2476 2506 } catch (IOException x) {
2477 2507 lastException = x;
2478 2508 }
2479 2509 }
2480 2510 return this;
2481 2511 }
2482 2512
2483 2513 // %[argument_index$][flags][width][.precision][t]conversion
2484 2514 private static final String formatSpecifier
2485 2515 = "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";
2486 2516
2487 2517 private static Pattern fsPattern = Pattern.compile(formatSpecifier);
2488 2518
2489 2519 /**
2490 2520 * Finds format specifiers in the format string.
2491 2521 */
2492 2522 private FormatString[] parse(String s) {
2493 2523 ArrayList<FormatString> al = new ArrayList<FormatString>();
2494 2524 Matcher m = fsPattern.matcher(s);
2495 2525 for (int i = 0, len = s.length(); i < len; ) {
2496 2526 if (m.find(i)) {
2497 2527 // Anything between the start of the string and the beginning
2498 2528 // of the format specifier is either fixed text or contains
2499 2529 // an invalid format string.
2500 2530 if (m.start() != i) {
2501 2531 // Make sure we didn't miss any invalid format specifiers
2502 2532 checkText(s, i, m.start());
2503 2533 // Assume previous characters were fixed text
2504 2534 al.add(new FixedString(s.substring(i, m.start())));
2505 2535 }
2506 2536
2507 2537 al.add(new FormatSpecifier(m));
2508 2538 i = m.end();
2509 2539 } else {
2510 2540 // No more valid format specifiers. Check for possible invalid
2511 2541 // format specifiers.
2512 2542 checkText(s, i, len);
2513 2543 // The rest of the string is fixed text
2514 2544 al.add(new FixedString(s.substring(i)));
2515 2545 break;
2516 2546 }
2517 2547 }
2518 2548 return al.toArray(new FormatString[al.size()]);
2519 2549 }
2520 2550
2521 2551 private static void checkText(String s, int start, int end) {
2522 2552 for (int i = start; i < end; i++) {
2523 2553 // Any '%' found in the region starts an invalid format specifier.
2524 2554 if (s.charAt(i) == '%') {
2525 2555 char c = (i == end - 1) ? '%' : s.charAt(i + 1);
2526 2556 throw new UnknownFormatConversionException(String.valueOf(c));
2527 2557 }
2528 2558 }
2529 2559 }
2530 2560
2531 2561 private interface FormatString {
2532 2562 int index();
2533 2563 void print(Object arg, Locale l) throws IOException;
2534 2564 String toString();
2535 2565 }
2536 2566
2537 2567 private class FixedString implements FormatString {
2538 2568 private String s;
2539 2569 FixedString(String s) { this.s = s; }
2540 2570 public int index() { return -2; }
2541 2571 public void print(Object arg, Locale l)
2542 2572 throws IOException { a.append(s); }
2543 2573 public String toString() { return s; }
2544 2574 }
2545 2575
2546 2576 public enum BigDecimalLayoutForm { SCIENTIFIC, DECIMAL_FLOAT };
2547 2577
2548 2578 private class FormatSpecifier implements FormatString {
2549 2579 private int index = -1;
2550 2580 private Flags f = Flags.NONE;
2551 2581 private int width;
2552 2582 private int precision;
2553 2583 private boolean dt = false;
2554 2584 private char c;
2555 2585
2556 2586 private int index(String s) {
2557 2587 if (s != null) {
2558 2588 try {
2559 2589 index = Integer.parseInt(s.substring(0, s.length() - 1));
2560 2590 } catch (NumberFormatException x) {
2561 2591 assert(false);
2562 2592 }
2563 2593 } else {
2564 2594 index = 0;
2565 2595 }
2566 2596 return index;
2567 2597 }
2568 2598
2569 2599 public int index() {
2570 2600 return index;
2571 2601 }
2572 2602
2573 2603 private Flags flags(String s) {
2574 2604 f = Flags.parse(s);
2575 2605 if (f.contains(Flags.PREVIOUS))
2576 2606 index = -1;
2577 2607 return f;
2578 2608 }
2579 2609
2580 2610 Flags flags() {
2581 2611 return f;
2582 2612 }
2583 2613
2584 2614 private int width(String s) {
2585 2615 width = -1;
2586 2616 if (s != null) {
2587 2617 try {
2588 2618 width = Integer.parseInt(s);
2589 2619 if (width < 0)
2590 2620 throw new IllegalFormatWidthException(width);
2591 2621 } catch (NumberFormatException x) {
2592 2622 assert(false);
2593 2623 }
2594 2624 }
2595 2625 return width;
2596 2626 }
2597 2627
2598 2628 int width() {
2599 2629 return width;
2600 2630 }
2601 2631
2602 2632 private int precision(String s) {
2603 2633 precision = -1;
2604 2634 if (s != null) {
2605 2635 try {
2606 2636 // remove the '.'
2607 2637 precision = Integer.parseInt(s.substring(1));
2608 2638 if (precision < 0)
2609 2639 throw new IllegalFormatPrecisionException(precision);
2610 2640 } catch (NumberFormatException x) {
2611 2641 assert(false);
2612 2642 }
2613 2643 }
2614 2644 return precision;
2615 2645 }
2616 2646
2617 2647 int precision() {
2618 2648 return precision;
2619 2649 }
2620 2650
2621 2651 private char conversion(String s) {
2622 2652 c = s.charAt(0);
2623 2653 if (!dt) {
2624 2654 if (!Conversion.isValid(c))
2625 2655 throw new UnknownFormatConversionException(String.valueOf(c));
2626 2656 if (Character.isUpperCase(c))
2627 2657 f.add(Flags.UPPERCASE);
2628 2658 c = Character.toLowerCase(c);
2629 2659 if (Conversion.isText(c))
2630 2660 index = -2;
2631 2661 }
2632 2662 return c;
2633 2663 }
2634 2664
2635 2665 private char conversion() {
2636 2666 return c;
2637 2667 }
2638 2668
2639 2669 FormatSpecifier(Matcher m) {
2640 2670 int idx = 1;
2641 2671
2642 2672 index(m.group(idx++));
2643 2673 flags(m.group(idx++));
2644 2674 width(m.group(idx++));
2645 2675 precision(m.group(idx++));
2646 2676
2647 2677 String tT = m.group(idx++);
2648 2678 if (tT != null) {
2649 2679 dt = true;
2650 2680 if (tT.equals("T"))
2651 2681 f.add(Flags.UPPERCASE);
2652 2682 }
2653 2683
2654 2684 conversion(m.group(idx));
2655 2685
2656 2686 if (dt)
2657 2687 checkDateTime();
2658 2688 else if (Conversion.isGeneral(c))
2659 2689 checkGeneral();
2660 2690 else if (Conversion.isCharacter(c))
2661 2691 checkCharacter();
2662 2692 else if (Conversion.isInteger(c))
2663 2693 checkInteger();
2664 2694 else if (Conversion.isFloat(c))
2665 2695 checkFloat();
2666 2696 else if (Conversion.isText(c))
2667 2697 checkText();
2668 2698 else
2669 2699 throw new UnknownFormatConversionException(String.valueOf(c));
2670 2700 }
2671 2701
2672 2702 public void print(Object arg, Locale l) throws IOException {
2673 2703 if (dt) {
2674 2704 printDateTime(arg, l);
2675 2705 return;
2676 2706 }
2677 2707 switch(c) {
2678 2708 case Conversion.DECIMAL_INTEGER:
2679 2709 case Conversion.OCTAL_INTEGER:
2680 2710 case Conversion.HEXADECIMAL_INTEGER:
2681 2711 printInteger(arg, l);
2682 2712 break;
2683 2713 case Conversion.SCIENTIFIC:
2684 2714 case Conversion.GENERAL:
2685 2715 case Conversion.DECIMAL_FLOAT:
2686 2716 case Conversion.HEXADECIMAL_FLOAT:
2687 2717 printFloat(arg, l);
2688 2718 break;
2689 2719 case Conversion.CHARACTER:
2690 2720 case Conversion.CHARACTER_UPPER:
2691 2721 printCharacter(arg);
2692 2722 break;
2693 2723 case Conversion.BOOLEAN:
2694 2724 printBoolean(arg);
2695 2725 break;
2696 2726 case Conversion.STRING:
2697 2727 printString(arg, l);
2698 2728 break;
2699 2729 case Conversion.HASHCODE:
2700 2730 printHashCode(arg);
2701 2731 break;
2702 2732 case Conversion.LINE_SEPARATOR:
2703 2733 a.append(System.lineSeparator());
2704 2734 break;
2705 2735 case Conversion.PERCENT_SIGN:
2706 2736 a.append('%');
2707 2737 break;
2708 2738 default:
2709 2739 assert false;
2710 2740 }
2711 2741 }
2712 2742
2713 2743 private void printInteger(Object arg, Locale l) throws IOException {
2714 2744 if (arg == null)
2715 2745 print("null");
2716 2746 else if (arg instanceof Byte)
2717 2747 print(((Byte)arg).byteValue(), l);
2718 2748 else if (arg instanceof Short)
2719 2749 print(((Short)arg).shortValue(), l);
2720 2750 else if (arg instanceof Integer)
2721 2751 print(((Integer)arg).intValue(), l);
2722 2752 else if (arg instanceof Long)
2723 2753 print(((Long)arg).longValue(), l);
2724 2754 else if (arg instanceof BigInteger)
2725 2755 print(((BigInteger)arg), l);
2726 2756 else
2727 2757 failConversion(c, arg);
2728 2758 }
2729 2759
2730 2760 private void printFloat(Object arg, Locale l) throws IOException {
2731 2761 if (arg == null)
2732 2762 print("null");
2733 2763 else if (arg instanceof Float)
2734 2764 print(((Float)arg).floatValue(), l);
2735 2765 else if (arg instanceof Double)
2736 2766 print(((Double)arg).doubleValue(), l);
2737 2767 else if (arg instanceof BigDecimal)
2738 2768 print(((BigDecimal)arg), l);
2739 2769 else
2740 2770 failConversion(c, arg);
2741 2771 }
2742 2772
2743 2773 private void printDateTime(Object arg, Locale l) throws IOException {
2744 2774 if (arg == null) {
2745 2775 print("null");
2746 2776 return;
2747 2777 }
2748 2778 Calendar cal = null;
2749 2779
2750 2780 // Instead of Calendar.setLenient(true), perhaps we should
2751 2781 // wrap the IllegalArgumentException that might be thrown?
2752 2782 if (arg instanceof Long) {
2753 2783 // Note that the following method uses an instance of the
2754 2784 // default time zone (TimeZone.getDefaultRef().
2755 2785 cal = Calendar.getInstance(l == null ? Locale.US : l);
2756 2786 cal.setTimeInMillis((Long)arg);
2757 2787 } else if (arg instanceof Date) {
2758 2788 // Note that the following method uses an instance of the
2759 2789 // default time zone (TimeZone.getDefaultRef().
2760 2790 cal = Calendar.getInstance(l == null ? Locale.US : l);
2761 2791 cal.setTime((Date)arg);
2762 2792 } else if (arg instanceof Calendar) {
2763 2793 cal = (Calendar) ((Calendar)arg).clone();
2764 2794 cal.setLenient(true);
2765 2795 } else {
2766 2796 failConversion(c, arg);
2767 2797 }
2768 2798 // Use the provided locale so that invocations of
2769 2799 // localizedMagnitude() use optimizations for null.
2770 2800 print(cal, c, l);
2771 2801 }
2772 2802
2773 2803 private void printCharacter(Object arg) throws IOException {
2774 2804 if (arg == null) {
2775 2805 print("null");
2776 2806 return;
2777 2807 }
2778 2808 String s = null;
2779 2809 if (arg instanceof Character) {
2780 2810 s = ((Character)arg).toString();
2781 2811 } else if (arg instanceof Byte) {
2782 2812 byte i = ((Byte)arg).byteValue();
2783 2813 if (Character.isValidCodePoint(i))
2784 2814 s = new String(Character.toChars(i));
2785 2815 else
2786 2816 throw new IllegalFormatCodePointException(i);
2787 2817 } else if (arg instanceof Short) {
2788 2818 short i = ((Short)arg).shortValue();
2789 2819 if (Character.isValidCodePoint(i))
2790 2820 s = new String(Character.toChars(i));
2791 2821 else
2792 2822 throw new IllegalFormatCodePointException(i);
2793 2823 } else if (arg instanceof Integer) {
2794 2824 int i = ((Integer)arg).intValue();
2795 2825 if (Character.isValidCodePoint(i))
2796 2826 s = new String(Character.toChars(i));
2797 2827 else
2798 2828 throw new IllegalFormatCodePointException(i);
2799 2829 } else {
2800 2830 failConversion(c, arg);
2801 2831 }
2802 2832 print(s);
2803 2833 }
2804 2834
2805 2835 private void printString(Object arg, Locale l) throws IOException {
2806 2836 if (arg instanceof Formattable) {
2807 2837 Formatter fmt = Formatter.this;
2808 2838 if (fmt.locale() != l)
2809 2839 fmt = new Formatter(fmt.out(), l);
2810 2840 ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision);
2811 2841 } else {
2812 2842 if (f.contains(Flags.ALTERNATE))
2813 2843 failMismatch(Flags.ALTERNATE, 's');
2814 2844 if (arg == null)
2815 2845 print("null");
2816 2846 else
2817 2847 print(arg.toString());
2818 2848 }
2819 2849 }
2820 2850
2821 2851 private void printBoolean(Object arg) throws IOException {
2822 2852 String s;
2823 2853 if (arg != null)
2824 2854 s = ((arg instanceof Boolean)
2825 2855 ? ((Boolean)arg).toString()
2826 2856 : Boolean.toString(true));
2827 2857 else
2828 2858 s = Boolean.toString(false);
2829 2859 print(s);
2830 2860 }
2831 2861
2832 2862 private void printHashCode(Object arg) throws IOException {
2833 2863 String s = (arg == null
2834 2864 ? "null"
2835 2865 : Integer.toHexString(arg.hashCode()));
2836 2866 print(s);
2837 2867 }
2838 2868
2839 2869 private void print(String s) throws IOException {
2840 2870 if (precision != -1 && precision < s.length())
2841 2871 s = s.substring(0, precision);
2842 2872 if (f.contains(Flags.UPPERCASE))
2843 2873 s = s.toUpperCase();
2844 2874 a.append(justify(s));
2845 2875 }
2846 2876
2847 2877 private String justify(String s) {
2848 2878 if (width == -1)
2849 2879 return s;
2850 2880 StringBuilder sb = new StringBuilder();
2851 2881 boolean pad = f.contains(Flags.LEFT_JUSTIFY);
2852 2882 int sp = width - s.length();
2853 2883 if (!pad)
2854 2884 for (int i = 0; i < sp; i++) sb.append(' ');
2855 2885 sb.append(s);
2856 2886 if (pad)
2857 2887 for (int i = 0; i < sp; i++) sb.append(' ');
2858 2888 return sb.toString();
2859 2889 }
2860 2890
2861 2891 public String toString() {
2862 2892 StringBuilder sb = new StringBuilder('%');
2863 2893 // Flags.UPPERCASE is set internally for legal conversions.
2864 2894 Flags dupf = f.dup().remove(Flags.UPPERCASE);
2865 2895 sb.append(dupf.toString());
2866 2896 if (index > 0)
2867 2897 sb.append(index).append('$');
2868 2898 if (width != -1)
2869 2899 sb.append(width);
2870 2900 if (precision != -1)
2871 2901 sb.append('.').append(precision);
2872 2902 if (dt)
2873 2903 sb.append(f.contains(Flags.UPPERCASE) ? 'T' : 't');
2874 2904 sb.append(f.contains(Flags.UPPERCASE)
2875 2905 ? Character.toUpperCase(c) : c);
2876 2906 return sb.toString();
2877 2907 }
2878 2908
2879 2909 private void checkGeneral() {
2880 2910 if ((c == Conversion.BOOLEAN || c == Conversion.HASHCODE)
2881 2911 && f.contains(Flags.ALTERNATE))
2882 2912 failMismatch(Flags.ALTERNATE, c);
2883 2913 // '-' requires a width
2884 2914 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
2885 2915 throw new MissingFormatWidthException(toString());
2886 2916 checkBadFlags(Flags.PLUS, Flags.LEADING_SPACE, Flags.ZERO_PAD,
2887 2917 Flags.GROUP, Flags.PARENTHESES);
2888 2918 }
2889 2919
2890 2920 private void checkDateTime() {
2891 2921 if (precision != -1)
2892 2922 throw new IllegalFormatPrecisionException(precision);
2893 2923 if (!DateTime.isValid(c))
2894 2924 throw new UnknownFormatConversionException("t" + c);
2895 2925 checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
2896 2926 Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
2897 2927 // '-' requires a width
2898 2928 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
2899 2929 throw new MissingFormatWidthException(toString());
2900 2930 }
2901 2931
2902 2932 private void checkCharacter() {
2903 2933 if (precision != -1)
2904 2934 throw new IllegalFormatPrecisionException(precision);
2905 2935 checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
2906 2936 Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
2907 2937 // '-' requires a width
2908 2938 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
2909 2939 throw new MissingFormatWidthException(toString());
2910 2940 }
2911 2941
2912 2942 private void checkInteger() {
2913 2943 checkNumeric();
2914 2944 if (precision != -1)
2915 2945 throw new IllegalFormatPrecisionException(precision);
2916 2946
2917 2947 if (c == Conversion.DECIMAL_INTEGER)
2918 2948 checkBadFlags(Flags.ALTERNATE);
2919 2949 else if (c == Conversion.OCTAL_INTEGER)
2920 2950 checkBadFlags(Flags.GROUP);
2921 2951 else
2922 2952 checkBadFlags(Flags.GROUP);
2923 2953 }
2924 2954
2925 2955 private void checkBadFlags(Flags ... badFlags) {
2926 2956 for (int i = 0; i < badFlags.length; i++)
2927 2957 if (f.contains(badFlags[i]))
2928 2958 failMismatch(badFlags[i], c);
2929 2959 }
2930 2960
2931 2961 private void checkFloat() {
2932 2962 checkNumeric();
2933 2963 if (c == Conversion.DECIMAL_FLOAT) {
2934 2964 } else if (c == Conversion.HEXADECIMAL_FLOAT) {
2935 2965 checkBadFlags(Flags.PARENTHESES, Flags.GROUP);
2936 2966 } else if (c == Conversion.SCIENTIFIC) {
2937 2967 checkBadFlags(Flags.GROUP);
2938 2968 } else if (c == Conversion.GENERAL) {
2939 2969 checkBadFlags(Flags.ALTERNATE);
2940 2970 }
2941 2971 }
2942 2972
2943 2973 private void checkNumeric() {
2944 2974 if (width != -1 && width < 0)
2945 2975 throw new IllegalFormatWidthException(width);
2946 2976
2947 2977 if (precision != -1 && precision < 0)
2948 2978 throw new IllegalFormatPrecisionException(precision);
2949 2979
2950 2980 // '-' and '0' require a width
2951 2981 if (width == -1
2952 2982 && (f.contains(Flags.LEFT_JUSTIFY) || f.contains(Flags.ZERO_PAD)))
2953 2983 throw new MissingFormatWidthException(toString());
2954 2984
2955 2985 // bad combination
2956 2986 if ((f.contains(Flags.PLUS) && f.contains(Flags.LEADING_SPACE))
2957 2987 || (f.contains(Flags.LEFT_JUSTIFY) && f.contains(Flags.ZERO_PAD)))
2958 2988 throw new IllegalFormatFlagsException(f.toString());
2959 2989 }
2960 2990
2961 2991 private void checkText() {
2962 2992 if (precision != -1)
2963 2993 throw new IllegalFormatPrecisionException(precision);
2964 2994 switch (c) {
2965 2995 case Conversion.PERCENT_SIGN:
2966 2996 if (f.valueOf() != Flags.LEFT_JUSTIFY.valueOf()
2967 2997 && f.valueOf() != Flags.NONE.valueOf())
2968 2998 throw new IllegalFormatFlagsException(f.toString());
2969 2999 // '-' requires a width
2970 3000 if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
2971 3001 throw new MissingFormatWidthException(toString());
2972 3002 break;
2973 3003 case Conversion.LINE_SEPARATOR:
2974 3004 if (width != -1)
2975 3005 throw new IllegalFormatWidthException(width);
2976 3006 if (f.valueOf() != Flags.NONE.valueOf())
2977 3007 throw new IllegalFormatFlagsException(f.toString());
2978 3008 break;
2979 3009 default:
2980 3010 assert false;
2981 3011 }
2982 3012 }
2983 3013
2984 3014 private void print(byte value, Locale l) throws IOException {
2985 3015 long v = value;
2986 3016 if (value < 0
2987 3017 && (c == Conversion.OCTAL_INTEGER
2988 3018 || c == Conversion.HEXADECIMAL_INTEGER)) {
2989 3019 v += (1L << 8);
2990 3020 assert v >= 0 : v;
2991 3021 }
2992 3022 print(v, l);
2993 3023 }
2994 3024
2995 3025 private void print(short value, Locale l) throws IOException {
2996 3026 long v = value;
2997 3027 if (value < 0
2998 3028 && (c == Conversion.OCTAL_INTEGER
2999 3029 || c == Conversion.HEXADECIMAL_INTEGER)) {
3000 3030 v += (1L << 16);
3001 3031 assert v >= 0 : v;
3002 3032 }
3003 3033 print(v, l);
3004 3034 }
3005 3035
3006 3036 private void print(int value, Locale l) throws IOException {
3007 3037 long v = value;
3008 3038 if (value < 0
3009 3039 && (c == Conversion.OCTAL_INTEGER
3010 3040 || c == Conversion.HEXADECIMAL_INTEGER)) {
3011 3041 v += (1L << 32);
3012 3042 assert v >= 0 : v;
3013 3043 }
3014 3044 print(v, l);
3015 3045 }
3016 3046
3017 3047 private void print(long value, Locale l) throws IOException {
3018 3048
3019 3049 StringBuilder sb = new StringBuilder();
3020 3050
3021 3051 if (c == Conversion.DECIMAL_INTEGER) {
3022 3052 boolean neg = value < 0;
3023 3053 char[] va;
3024 3054 if (value < 0)
3025 3055 va = Long.toString(value, 10).substring(1).toCharArray();
3026 3056 else
3027 3057 va = Long.toString(value, 10).toCharArray();
3028 3058
3029 3059 // leading sign indicator
3030 3060 leadingSign(sb, neg);
3031 3061
3032 3062 // the value
3033 3063 localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l);
3034 3064
3035 3065 // trailing sign indicator
3036 3066 trailingSign(sb, neg);
3037 3067 } else if (c == Conversion.OCTAL_INTEGER) {
3038 3068 checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
3039 3069 Flags.PLUS);
3040 3070 String s = Long.toOctalString(value);
3041 3071 int len = (f.contains(Flags.ALTERNATE)
3042 3072 ? s.length() + 1
3043 3073 : s.length());
3044 3074
3045 3075 // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
3046 3076 if (f.contains(Flags.ALTERNATE))
3047 3077 sb.append('0');
3048 3078 if (f.contains(Flags.ZERO_PAD))
3049 3079 for (int i = 0; i < width - len; i++) sb.append('0');
3050 3080 sb.append(s);
3051 3081 } else if (c == Conversion.HEXADECIMAL_INTEGER) {
3052 3082 checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
3053 3083 Flags.PLUS);
3054 3084 String s = Long.toHexString(value);
3055 3085 int len = (f.contains(Flags.ALTERNATE)
3056 3086 ? s.length() + 2
3057 3087 : s.length());
3058 3088
3059 3089 // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
3060 3090 if (f.contains(Flags.ALTERNATE))
3061 3091 sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
3062 3092 if (f.contains(Flags.ZERO_PAD))
3063 3093 for (int i = 0; i < width - len; i++) sb.append('0');
3064 3094 if (f.contains(Flags.UPPERCASE))
3065 3095 s = s.toUpperCase();
3066 3096 sb.append(s);
3067 3097 }
3068 3098
3069 3099 // justify based on width
3070 3100 a.append(justify(sb.toString()));
3071 3101 }
3072 3102
3073 3103 // neg := val < 0
3074 3104 private StringBuilder leadingSign(StringBuilder sb, boolean neg) {
3075 3105 if (!neg) {
3076 3106 if (f.contains(Flags.PLUS)) {
3077 3107 sb.append('+');
3078 3108 } else if (f.contains(Flags.LEADING_SPACE)) {
3079 3109 sb.append(' ');
3080 3110 }
3081 3111 } else {
3082 3112 if (f.contains(Flags.PARENTHESES))
3083 3113 sb.append('(');
3084 3114 else
3085 3115 sb.append('-');
3086 3116 }
3087 3117 return sb;
3088 3118 }
3089 3119
3090 3120 // neg := val < 0
3091 3121 private StringBuilder trailingSign(StringBuilder sb, boolean neg) {
3092 3122 if (neg && f.contains(Flags.PARENTHESES))
3093 3123 sb.append(')');
3094 3124 return sb;
3095 3125 }
3096 3126
3097 3127 private void print(BigInteger value, Locale l) throws IOException {
3098 3128 StringBuilder sb = new StringBuilder();
3099 3129 boolean neg = value.signum() == -1;
3100 3130 BigInteger v = value.abs();
3101 3131
3102 3132 // leading sign indicator
3103 3133 leadingSign(sb, neg);
3104 3134
3105 3135 // the value
3106 3136 if (c == Conversion.DECIMAL_INTEGER) {
3107 3137 char[] va = v.toString().toCharArray();
3108 3138 localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l);
3109 3139 } else if (c == Conversion.OCTAL_INTEGER) {
3110 3140 String s = v.toString(8);
3111 3141
3112 3142 int len = s.length() + sb.length();
3113 3143 if (neg && f.contains(Flags.PARENTHESES))
3114 3144 len++;
3115 3145
3116 3146 // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
3117 3147 if (f.contains(Flags.ALTERNATE)) {
3118 3148 len++;
3119 3149 sb.append('0');
3120 3150 }
3121 3151 if (f.contains(Flags.ZERO_PAD)) {
3122 3152 for (int i = 0; i < width - len; i++)
3123 3153 sb.append('0');
3124 3154 }
3125 3155 sb.append(s);
3126 3156 } else if (c == Conversion.HEXADECIMAL_INTEGER) {
3127 3157 String s = v.toString(16);
3128 3158
3129 3159 int len = s.length() + sb.length();
3130 3160 if (neg && f.contains(Flags.PARENTHESES))
3131 3161 len++;
3132 3162
3133 3163 // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
3134 3164 if (f.contains(Flags.ALTERNATE)) {
3135 3165 len += 2;
3136 3166 sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
3137 3167 }
3138 3168 if (f.contains(Flags.ZERO_PAD))
3139 3169 for (int i = 0; i < width - len; i++)
3140 3170 sb.append('0');
3141 3171 if (f.contains(Flags.UPPERCASE))
3142 3172 s = s.toUpperCase();
3143 3173 sb.append(s);
3144 3174 }
3145 3175
3146 3176 // trailing sign indicator
3147 3177 trailingSign(sb, (value.signum() == -1));
3148 3178
3149 3179 // justify based on width
3150 3180 a.append(justify(sb.toString()));
3151 3181 }
3152 3182
3153 3183 private void print(float value, Locale l) throws IOException {
3154 3184 print((double) value, l);
3155 3185 }
3156 3186
3157 3187 private void print(double value, Locale l) throws IOException {
3158 3188 StringBuilder sb = new StringBuilder();
3159 3189 boolean neg = Double.compare(value, 0.0) == -1;
3160 3190
3161 3191 if (!Double.isNaN(value)) {
3162 3192 double v = Math.abs(value);
3163 3193
3164 3194 // leading sign indicator
3165 3195 leadingSign(sb, neg);
3166 3196
3167 3197 // the value
3168 3198 if (!Double.isInfinite(v))
3169 3199 print(sb, v, l, f, c, precision, neg);
3170 3200 else
3171 3201 sb.append(f.contains(Flags.UPPERCASE)
3172 3202 ? "INFINITY" : "Infinity");
3173 3203
3174 3204 // trailing sign indicator
3175 3205 trailingSign(sb, neg);
3176 3206 } else {
3177 3207 sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN");
3178 3208 }
3179 3209
3180 3210 // justify based on width
3181 3211 a.append(justify(sb.toString()));
3182 3212 }
3183 3213
3184 3214 // !Double.isInfinite(value) && !Double.isNaN(value)
3185 3215 private void print(StringBuilder sb, double value, Locale l,
3186 3216 Flags f, char c, int precision, boolean neg)
3187 3217 throws IOException
3188 3218 {
3189 3219 if (c == Conversion.SCIENTIFIC) {
3190 3220 // Create a new FormattedFloatingDecimal with the desired
3191 3221 // precision.
3192 3222 int prec = (precision == -1 ? 6 : precision);
3193 3223
3194 3224 FormattedFloatingDecimal fd
3195 3225 = new FormattedFloatingDecimal(value, prec,
3196 3226 FormattedFloatingDecimal.Form.SCIENTIFIC);
3197 3227
3198 3228 char[] v = new char[MAX_FD_CHARS];
3199 3229 int len = fd.getChars(v);
3200 3230
3201 3231 char[] mant = addZeros(mantissa(v, len), prec);
3202 3232
3203 3233 // If the precision is zero and the '#' flag is set, add the
3204 3234 // requested decimal point.
3205 3235 if (f.contains(Flags.ALTERNATE) && (prec == 0))
3206 3236 mant = addDot(mant);
3207 3237
3208 3238 char[] exp = (value == 0.0)
3209 3239 ? new char[] {'+','0','0'} : exponent(v, len);
3210 3240
3211 3241 int newW = width;
3212 3242 if (width != -1)
3213 3243 newW = adjustWidth(width - exp.length - 1, f, neg);
3214 3244 localizedMagnitude(sb, mant, f, newW, l);
3215 3245
3216 3246 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
3217 3247
3218 3248 Flags flags = f.dup().remove(Flags.GROUP);
3219 3249 char sign = exp[0];
3220 3250 assert(sign == '+' || sign == '-');
3221 3251 sb.append(sign);
3222 3252
3223 3253 char[] tmp = new char[exp.length - 1];
3224 3254 System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
3225 3255 sb.append(localizedMagnitude(null, tmp, flags, -1, l));
3226 3256 } else if (c == Conversion.DECIMAL_FLOAT) {
3227 3257 // Create a new FormattedFloatingDecimal with the desired
3228 3258 // precision.
3229 3259 int prec = (precision == -1 ? 6 : precision);
3230 3260
3231 3261 FormattedFloatingDecimal fd
3232 3262 = new FormattedFloatingDecimal(value, prec,
3233 3263 FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
3234 3264
3235 3265 // MAX_FD_CHARS + 1 (round?)
3236 3266 char[] v = new char[MAX_FD_CHARS + 1
3237 3267 + Math.abs(fd.getExponent())];
3238 3268 int len = fd.getChars(v);
3239 3269
3240 3270 char[] mant = addZeros(mantissa(v, len), prec);
3241 3271
3242 3272 // If the precision is zero and the '#' flag is set, add the
3243 3273 // requested decimal point.
3244 3274 if (f.contains(Flags.ALTERNATE) && (prec == 0))
3245 3275 mant = addDot(mant);
3246 3276
3247 3277 int newW = width;
3248 3278 if (width != -1)
3249 3279 newW = adjustWidth(width, f, neg);
3250 3280 localizedMagnitude(sb, mant, f, newW, l);
3251 3281 } else if (c == Conversion.GENERAL) {
3252 3282 int prec = precision;
3253 3283 if (precision == -1)
3254 3284 prec = 6;
3255 3285 else if (precision == 0)
3256 3286 prec = 1;
3257 3287
3258 3288 FormattedFloatingDecimal fd
3259 3289 = new FormattedFloatingDecimal(value, prec,
3260 3290 FormattedFloatingDecimal.Form.GENERAL);
3261 3291
3262 3292 // MAX_FD_CHARS + 1 (round?)
3263 3293 char[] v = new char[MAX_FD_CHARS + 1
3264 3294 + Math.abs(fd.getExponent())];
3265 3295 int len = fd.getChars(v);
3266 3296
3267 3297 char[] exp = exponent(v, len);
3268 3298 if (exp != null) {
3269 3299 prec -= 1;
3270 3300 } else {
3271 3301 prec = prec - (value == 0 ? 0 : fd.getExponentRounded()) - 1;
3272 3302 }
3273 3303
3274 3304 char[] mant = addZeros(mantissa(v, len), prec);
3275 3305 // If the precision is zero and the '#' flag is set, add the
3276 3306 // requested decimal point.
3277 3307 if (f.contains(Flags.ALTERNATE) && (prec == 0))
3278 3308 mant = addDot(mant);
3279 3309
3280 3310 int newW = width;
3281 3311 if (width != -1) {
3282 3312 if (exp != null)
3283 3313 newW = adjustWidth(width - exp.length - 1, f, neg);
3284 3314 else
3285 3315 newW = adjustWidth(width, f, neg);
3286 3316 }
3287 3317 localizedMagnitude(sb, mant, f, newW, l);
3288 3318
3289 3319 if (exp != null) {
3290 3320 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
3291 3321
3292 3322 Flags flags = f.dup().remove(Flags.GROUP);
3293 3323 char sign = exp[0];
3294 3324 assert(sign == '+' || sign == '-');
3295 3325 sb.append(sign);
3296 3326
3297 3327 char[] tmp = new char[exp.length - 1];
3298 3328 System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
3299 3329 sb.append(localizedMagnitude(null, tmp, flags, -1, l));
3300 3330 }
3301 3331 } else if (c == Conversion.HEXADECIMAL_FLOAT) {
3302 3332 int prec = precision;
3303 3333 if (precision == -1)
3304 3334 // assume that we want all of the digits
3305 3335 prec = 0;
3306 3336 else if (precision == 0)
3307 3337 prec = 1;
3308 3338
3309 3339 String s = hexDouble(value, prec);
3310 3340
3311 3341 char[] va;
3312 3342 boolean upper = f.contains(Flags.UPPERCASE);
3313 3343 sb.append(upper ? "0X" : "0x");
3314 3344
3315 3345 if (f.contains(Flags.ZERO_PAD))
3316 3346 for (int i = 0; i < width - s.length() - 2; i++)
3317 3347 sb.append('0');
3318 3348
3319 3349 int idx = s.indexOf('p');
3320 3350 va = s.substring(0, idx).toCharArray();
3321 3351 if (upper) {
3322 3352 String tmp = new String(va);
3323 3353 // don't localize hex
3324 3354 tmp = tmp.toUpperCase(Locale.US);
3325 3355 va = tmp.toCharArray();
3326 3356 }
3327 3357 sb.append(prec != 0 ? addZeros(va, prec) : va);
3328 3358 sb.append(upper ? 'P' : 'p');
3329 3359 sb.append(s.substring(idx+1));
3330 3360 }
3331 3361 }
3332 3362
3333 3363 private char[] mantissa(char[] v, int len) {
3334 3364 int i;
3335 3365 for (i = 0; i < len; i++) {
3336 3366 if (v[i] == 'e')
3337 3367 break;
3338 3368 }
3339 3369 char[] tmp = new char[i];
3340 3370 System.arraycopy(v, 0, tmp, 0, i);
3341 3371 return tmp;
3342 3372 }
3343 3373
3344 3374 private char[] exponent(char[] v, int len) {
3345 3375 int i;
3346 3376 for (i = len - 1; i >= 0; i--) {
3347 3377 if (v[i] == 'e')
3348 3378 break;
3349 3379 }
3350 3380 if (i == -1)
3351 3381 return null;
3352 3382 char[] tmp = new char[len - i - 1];
3353 3383 System.arraycopy(v, i + 1, tmp, 0, len - i - 1);
3354 3384 return tmp;
3355 3385 }
3356 3386
3357 3387 // Add zeros to the requested precision.
3358 3388 private char[] addZeros(char[] v, int prec) {
3359 3389 // Look for the dot. If we don't find one, the we'll need to add
3360 3390 // it before we add the zeros.
3361 3391 int i;
3362 3392 for (i = 0; i < v.length; i++) {
3363 3393 if (v[i] == '.')
3364 3394 break;
3365 3395 }
3366 3396 boolean needDot = false;
3367 3397 if (i == v.length) {
3368 3398 needDot = true;
3369 3399 }
3370 3400
3371 3401 // Determine existing precision.
3372 3402 int outPrec = v.length - i - (needDot ? 0 : 1);
3373 3403 assert (outPrec <= prec);
3374 3404 if (outPrec == prec)
3375 3405 return v;
3376 3406
3377 3407 // Create new array with existing contents.
3378 3408 char[] tmp
3379 3409 = new char[v.length + prec - outPrec + (needDot ? 1 : 0)];
3380 3410 System.arraycopy(v, 0, tmp, 0, v.length);
3381 3411
3382 3412 // Add dot if previously determined to be necessary.
3383 3413 int start = v.length;
3384 3414 if (needDot) {
3385 3415 tmp[v.length] = '.';
3386 3416 start++;
3387 3417 }
3388 3418
3389 3419 // Add zeros.
3390 3420 for (int j = start; j < tmp.length; j++)
3391 3421 tmp[j] = '0';
3392 3422
3393 3423 return tmp;
3394 3424 }
3395 3425
3396 3426 // Method assumes that d > 0.
3397 3427 private String hexDouble(double d, int prec) {
3398 3428 // Let Double.toHexString handle simple cases
3399 3429 if(!FpUtils.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13)
3400 3430 // remove "0x"
3401 3431 return Double.toHexString(d).substring(2);
3402 3432 else {
3403 3433 assert(prec >= 1 && prec <= 12);
3404 3434
3405 3435 int exponent = FpUtils.getExponent(d);
3406 3436 boolean subnormal
3407 3437 = (exponent == DoubleConsts.MIN_EXPONENT - 1);
3408 3438
3409 3439 // If this is subnormal input so normalize (could be faster to
3410 3440 // do as integer operation).
3411 3441 if (subnormal) {
3412 3442 scaleUp = FpUtils.scalb(1.0, 54);
3413 3443 d *= scaleUp;
3414 3444 // Calculate the exponent. This is not just exponent + 54
3415 3445 // since the former is not the normalized exponent.
3416 3446 exponent = FpUtils.getExponent(d);
3417 3447 assert exponent >= DoubleConsts.MIN_EXPONENT &&
3418 3448 exponent <= DoubleConsts.MAX_EXPONENT: exponent;
3419 3449 }
3420 3450
3421 3451 int precision = 1 + prec*4;
3422 3452 int shiftDistance
3423 3453 = DoubleConsts.SIGNIFICAND_WIDTH - precision;
3424 3454 assert(shiftDistance >= 1 && shiftDistance < DoubleConsts.SIGNIFICAND_WIDTH);
3425 3455
3426 3456 long doppel = Double.doubleToLongBits(d);
3427 3457 // Deterime the number of bits to keep.
3428 3458 long newSignif
3429 3459 = (doppel & (DoubleConsts.EXP_BIT_MASK
3430 3460 | DoubleConsts.SIGNIF_BIT_MASK))
3431 3461 >> shiftDistance;
3432 3462 // Bits to round away.
3433 3463 long roundingBits = doppel & ~(~0L << shiftDistance);
3434 3464
3435 3465 // To decide how to round, look at the low-order bit of the
3436 3466 // working significand, the highest order discarded bit (the
3437 3467 // round bit) and whether any of the lower order discarded bits
3438 3468 // are nonzero (the sticky bit).
3439 3469
3440 3470 boolean leastZero = (newSignif & 0x1L) == 0L;
3441 3471 boolean round
3442 3472 = ((1L << (shiftDistance - 1) ) & roundingBits) != 0L;
3443 3473 boolean sticky = shiftDistance > 1 &&
3444 3474 (~(1L<< (shiftDistance - 1)) & roundingBits) != 0;
3445 3475 if((leastZero && round && sticky) || (!leastZero && round)) {
3446 3476 newSignif++;
3447 3477 }
3448 3478
3449 3479 long signBit = doppel & DoubleConsts.SIGN_BIT_MASK;
3450 3480 newSignif = signBit | (newSignif << shiftDistance);
3451 3481 double result = Double.longBitsToDouble(newSignif);
3452 3482
3453 3483 if (Double.isInfinite(result) ) {
3454 3484 // Infinite result generated by rounding
3455 3485 return "1.0p1024";
3456 3486 } else {
3457 3487 String res = Double.toHexString(result).substring(2);
3458 3488 if (!subnormal)
3459 3489 return res;
3460 3490 else {
3461 3491 // Create a normalized subnormal string.
3462 3492 int idx = res.indexOf('p');
3463 3493 if (idx == -1) {
3464 3494 // No 'p' character in hex string.
3465 3495 assert false;
3466 3496 return null;
3467 3497 } else {
3468 3498 // Get exponent and append at the end.
3469 3499 String exp = res.substring(idx + 1);
3470 3500 int iexp = Integer.parseInt(exp) -54;
3471 3501 return res.substring(0, idx) + "p"
3472 3502 + Integer.toString(iexp);
3473 3503 }
3474 3504 }
3475 3505 }
3476 3506 }
3477 3507 }
3478 3508
3479 3509 private void print(BigDecimal value, Locale l) throws IOException {
3480 3510 if (c == Conversion.HEXADECIMAL_FLOAT)
3481 3511 failConversion(c, value);
3482 3512 StringBuilder sb = new StringBuilder();
3483 3513 boolean neg = value.signum() == -1;
3484 3514 BigDecimal v = value.abs();
3485 3515 // leading sign indicator
3486 3516 leadingSign(sb, neg);
3487 3517
3488 3518 // the value
3489 3519 print(sb, v, l, f, c, precision, neg);
3490 3520
3491 3521 // trailing sign indicator
3492 3522 trailingSign(sb, neg);
3493 3523
3494 3524 // justify based on width
3495 3525 a.append(justify(sb.toString()));
3496 3526 }
3497 3527
3498 3528 // value > 0
3499 3529 private void print(StringBuilder sb, BigDecimal value, Locale l,
3500 3530 Flags f, char c, int precision, boolean neg)
3501 3531 throws IOException
3502 3532 {
3503 3533 if (c == Conversion.SCIENTIFIC) {
3504 3534 // Create a new BigDecimal with the desired precision.
3505 3535 int prec = (precision == -1 ? 6 : precision);
3506 3536 int scale = value.scale();
3507 3537 int origPrec = value.precision();
3508 3538 int nzeros = 0;
3509 3539 int compPrec;
3510 3540
3511 3541 if (prec > origPrec - 1) {
3512 3542 compPrec = origPrec;
3513 3543 nzeros = prec - (origPrec - 1);
3514 3544 } else {
3515 3545 compPrec = prec + 1;
3516 3546 }
3517 3547
3518 3548 MathContext mc = new MathContext(compPrec);
3519 3549 BigDecimal v
3520 3550 = new BigDecimal(value.unscaledValue(), scale, mc);
3521 3551
3522 3552 BigDecimalLayout bdl
3523 3553 = new BigDecimalLayout(v.unscaledValue(), v.scale(),
3524 3554 BigDecimalLayoutForm.SCIENTIFIC);
3525 3555
3526 3556 char[] mant = bdl.mantissa();
3527 3557
3528 3558 // Add a decimal point if necessary. The mantissa may not
3529 3559 // contain a decimal point if the scale is zero (the internal
3530 3560 // representation has no fractional part) or the original
3531 3561 // precision is one. Append a decimal point if '#' is set or if
3532 3562 // we require zero padding to get to the requested precision.
3533 3563 if ((origPrec == 1 || !bdl.hasDot())
3534 3564 && (nzeros > 0 || (f.contains(Flags.ALTERNATE))))
3535 3565 mant = addDot(mant);
3536 3566
3537 3567 // Add trailing zeros in the case precision is greater than
3538 3568 // the number of available digits after the decimal separator.
3539 3569 mant = trailingZeros(mant, nzeros);
3540 3570
3541 3571 char[] exp = bdl.exponent();
3542 3572 int newW = width;
3543 3573 if (width != -1)
3544 3574 newW = adjustWidth(width - exp.length - 1, f, neg);
3545 3575 localizedMagnitude(sb, mant, f, newW, l);
3546 3576
3547 3577 sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
3548 3578
3549 3579 Flags flags = f.dup().remove(Flags.GROUP);
3550 3580 char sign = exp[0];
3551 3581 assert(sign == '+' || sign == '-');
3552 3582 sb.append(exp[0]);
3553 3583
3554 3584 char[] tmp = new char[exp.length - 1];
3555 3585 System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
3556 3586 sb.append(localizedMagnitude(null, tmp, flags, -1, l));
3557 3587 } else if (c == Conversion.DECIMAL_FLOAT) {
3558 3588 // Create a new BigDecimal with the desired precision.
3559 3589 int prec = (precision == -1 ? 6 : precision);
3560 3590 int scale = value.scale();
3561 3591
3562 3592 if (scale > prec) {
3563 3593 // more "scale" digits than the requested "precision
3564 3594 int compPrec = value.precision();
3565 3595 if (compPrec <= scale) {
3566 3596 // case of 0.xxxxxx
3567 3597 value = value.setScale(prec, RoundingMode.HALF_UP);
3568 3598 } else {
3569 3599 compPrec -= (scale - prec);
3570 3600 value = new BigDecimal(value.unscaledValue(),
3571 3601 scale,
3572 3602 new MathContext(compPrec));
3573 3603 }
3574 3604 }
3575 3605 BigDecimalLayout bdl = new BigDecimalLayout(
3576 3606 value.unscaledValue(),
3577 3607 value.scale(),
3578 3608 BigDecimalLayoutForm.DECIMAL_FLOAT);
3579 3609
3580 3610 char mant[] = bdl.mantissa();
3581 3611 int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0);
3582 3612
3583 3613 // Add a decimal point if necessary. The mantissa may not
3584 3614 // contain a decimal point if the scale is zero (the internal
3585 3615 // representation has no fractional part). Append a decimal
3586 3616 // point if '#' is set or we require zero padding to get to the
3587 3617 // requested precision.
3588 3618 if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) || nzeros > 0))
3589 3619 mant = addDot(bdl.mantissa());
3590 3620
3591 3621 // Add trailing zeros if the precision is greater than the
3592 3622 // number of available digits after the decimal separator.
3593 3623 mant = trailingZeros(mant, nzeros);
3594 3624
3595 3625 localizedMagnitude(sb, mant, f, adjustWidth(width, f, neg), l);
3596 3626 } else if (c == Conversion.GENERAL) {
3597 3627 int prec = precision;
3598 3628 if (precision == -1)
3599 3629 prec = 6;
3600 3630 else if (precision == 0)
3601 3631 prec = 1;
3602 3632
3603 3633 BigDecimal tenToTheNegFour = BigDecimal.valueOf(1, 4);
3604 3634 BigDecimal tenToThePrec = BigDecimal.valueOf(1, -prec);
3605 3635 if ((value.equals(BigDecimal.ZERO))
3606 3636 || ((value.compareTo(tenToTheNegFour) != -1)
3607 3637 && (value.compareTo(tenToThePrec) == -1))) {
3608 3638
3609 3639 int e = - value.scale()
3610 3640 + (value.unscaledValue().toString().length() - 1);
3611 3641
3612 3642 // xxx.yyy
3613 3643 // g precision (# sig digits) = #x + #y
3614 3644 // f precision = #y
3615 3645 // exponent = #x - 1
3616 3646 // => f precision = g precision - exponent - 1
3617 3647 // 0.000zzz
3618 3648 // g precision (# sig digits) = #z
3619 3649 // f precision = #0 (after '.') + #z
3620 3650 // exponent = - #0 (after '.') - 1
3621 3651 // => f precision = g precision - exponent - 1
3622 3652 prec = prec - e - 1;
3623 3653
3624 3654 print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec,
3625 3655 neg);
3626 3656 } else {
3627 3657 print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg);
3628 3658 }
3629 3659 } else if (c == Conversion.HEXADECIMAL_FLOAT) {
3630 3660 // This conversion isn't supported. The error should be
3631 3661 // reported earlier.
3632 3662 assert false;
3633 3663 }
3634 3664 }
3635 3665
3636 3666 private class BigDecimalLayout {
3637 3667 private StringBuilder mant;
3638 3668 private StringBuilder exp;
3639 3669 private boolean dot = false;
3640 3670 private int scale;
3641 3671
3642 3672 public BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
3643 3673 layout(intVal, scale, form);
3644 3674 }
3645 3675
3646 3676 public boolean hasDot() {
3647 3677 return dot;
3648 3678 }
3649 3679
3650 3680 public int scale() {
3651 3681 return scale;
3652 3682 }
3653 3683
3654 3684 // char[] with canonical string representation
3655 3685 public char[] layoutChars() {
3656 3686 StringBuilder sb = new StringBuilder(mant);
3657 3687 if (exp != null) {
3658 3688 sb.append('E');
3659 3689 sb.append(exp);
3660 3690 }
3661 3691 return toCharArray(sb);
3662 3692 }
3663 3693
3664 3694 public char[] mantissa() {
3665 3695 return toCharArray(mant);
3666 3696 }
3667 3697
3668 3698 // The exponent will be formatted as a sign ('+' or '-') followed
3669 3699 // by the exponent zero-padded to include at least two digits.
3670 3700 public char[] exponent() {
3671 3701 return toCharArray(exp);
3672 3702 }
3673 3703
3674 3704 private char[] toCharArray(StringBuilder sb) {
3675 3705 if (sb == null)
3676 3706 return null;
3677 3707 char[] result = new char[sb.length()];
3678 3708 sb.getChars(0, result.length, result, 0);
3679 3709 return result;
3680 3710 }
3681 3711
3682 3712 private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
3683 3713 char coeff[] = intVal.toString().toCharArray();
3684 3714 this.scale = scale;
3685 3715
3686 3716 // Construct a buffer, with sufficient capacity for all cases.
3687 3717 // If E-notation is needed, length will be: +1 if negative, +1
3688 3718 // if '.' needed, +2 for "E+", + up to 10 for adjusted
3689 3719 // exponent. Otherwise it could have +1 if negative, plus
3690 3720 // leading "0.00000"
3691 3721 mant = new StringBuilder(coeff.length + 14);
3692 3722
3693 3723 if (scale == 0) {
3694 3724 int len = coeff.length;
3695 3725 if (len > 1) {
3696 3726 mant.append(coeff[0]);
3697 3727 if (form == BigDecimalLayoutForm.SCIENTIFIC) {
3698 3728 mant.append('.');
3699 3729 dot = true;
3700 3730 mant.append(coeff, 1, len - 1);
3701 3731 exp = new StringBuilder("+");
3702 3732 if (len < 10)
3703 3733 exp.append("0").append(len - 1);
3704 3734 else
3705 3735 exp.append(len - 1);
3706 3736 } else {
3707 3737 mant.append(coeff, 1, len - 1);
3708 3738 }
3709 3739 } else {
3710 3740 mant.append(coeff);
3711 3741 if (form == BigDecimalLayoutForm.SCIENTIFIC)
3712 3742 exp = new StringBuilder("+00");
3713 3743 }
3714 3744 return;
3715 3745 }
3716 3746 long adjusted = -(long) scale + (coeff.length - 1);
3717 3747 if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) {
3718 3748 // count of padding zeros
3719 3749 int pad = scale - coeff.length;
3720 3750 if (pad >= 0) {
3721 3751 // 0.xxx form
3722 3752 mant.append("0.");
3723 3753 dot = true;
3724 3754 for (; pad > 0 ; pad--) mant.append('0');
3725 3755 mant.append(coeff);
3726 3756 } else {
3727 3757 if (-pad < coeff.length) {
3728 3758 // xx.xx form
3729 3759 mant.append(coeff, 0, -pad);
3730 3760 mant.append('.');
3731 3761 dot = true;
3732 3762 mant.append(coeff, -pad, scale);
3733 3763 } else {
3734 3764 // xx form
3735 3765 mant.append(coeff, 0, coeff.length);
3736 3766 for (int i = 0; i < -scale; i++)
3737 3767 mant.append('0');
3738 3768 this.scale = 0;
3739 3769 }
3740 3770 }
3741 3771 } else {
3742 3772 // x.xxx form
3743 3773 mant.append(coeff[0]);
3744 3774 if (coeff.length > 1) {
3745 3775 mant.append('.');
3746 3776 dot = true;
3747 3777 mant.append(coeff, 1, coeff.length-1);
3748 3778 }
3749 3779 exp = new StringBuilder();
3750 3780 if (adjusted != 0) {
3751 3781 long abs = Math.abs(adjusted);
3752 3782 // require sign
3753 3783 exp.append(adjusted < 0 ? '-' : '+');
3754 3784 if (abs < 10)
3755 3785 exp.append('0');
3756 3786 exp.append(abs);
3757 3787 } else {
3758 3788 exp.append("+00");
3759 3789 }
3760 3790 }
3761 3791 }
3762 3792 }
3763 3793
3764 3794 private int adjustWidth(int width, Flags f, boolean neg) {
3765 3795 int newW = width;
3766 3796 if (newW != -1 && neg && f.contains(Flags.PARENTHESES))
3767 3797 newW--;
3768 3798 return newW;
3769 3799 }
3770 3800
3771 3801 // Add a '.' to th mantissa if required
3772 3802 private char[] addDot(char[] mant) {
3773 3803 char[] tmp = mant;
3774 3804 tmp = new char[mant.length + 1];
3775 3805 System.arraycopy(mant, 0, tmp, 0, mant.length);
3776 3806 tmp[tmp.length - 1] = '.';
3777 3807 return tmp;
3778 3808 }
3779 3809
3780 3810 // Add trailing zeros in the case precision is greater than the number
3781 3811 // of available digits after the decimal separator.
3782 3812 private char[] trailingZeros(char[] mant, int nzeros) {
3783 3813 char[] tmp = mant;
3784 3814 if (nzeros > 0) {
3785 3815 tmp = new char[mant.length + nzeros];
3786 3816 System.arraycopy(mant, 0, tmp, 0, mant.length);
3787 3817 for (int i = mant.length; i < tmp.length; i++)
3788 3818 tmp[i] = '0';
3789 3819 }
3790 3820 return tmp;
3791 3821 }
3792 3822
3793 3823 private void print(Calendar t, char c, Locale l) throws IOException
3794 3824 {
3795 3825 StringBuilder sb = new StringBuilder();
3796 3826 print(sb, t, c, l);
3797 3827
3798 3828 // justify based on width
3799 3829 String s = justify(sb.toString());
3800 3830 if (f.contains(Flags.UPPERCASE))
3801 3831 s = s.toUpperCase();
3802 3832
3803 3833 a.append(s);
3804 3834 }
3805 3835
3806 3836 private Appendable print(StringBuilder sb, Calendar t, char c,
3807 3837 Locale l)
3808 3838 throws IOException
3809 3839 {
3810 3840 assert(width == -1);
3811 3841 if (sb == null)
3812 3842 sb = new StringBuilder();
3813 3843 switch (c) {
3814 3844 case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23)
3815 3845 case DateTime.HOUR_0: // 'I' (01 - 12)
3816 3846 case DateTime.HOUR_OF_DAY: // 'k' (0 - 23) -- like H
3817 3847 case DateTime.HOUR: { // 'l' (1 - 12) -- like I
3818 3848 int i = t.get(Calendar.HOUR_OF_DAY);
3819 3849 if (c == DateTime.HOUR_0 || c == DateTime.HOUR)
3820 3850 i = (i == 0 || i == 12 ? 12 : i % 12);
3821 3851 Flags flags = (c == DateTime.HOUR_OF_DAY_0
3822 3852 || c == DateTime.HOUR_0
3823 3853 ? Flags.ZERO_PAD
3824 3854 : Flags.NONE);
3825 3855 sb.append(localizedMagnitude(null, i, flags, 2, l));
3826 3856 break;
3827 3857 }
3828 3858 case DateTime.MINUTE: { // 'M' (00 - 59)
3829 3859 int i = t.get(Calendar.MINUTE);
3830 3860 Flags flags = Flags.ZERO_PAD;
3831 3861 sb.append(localizedMagnitude(null, i, flags, 2, l));
3832 3862 break;
3833 3863 }
3834 3864 case DateTime.NANOSECOND: { // 'N' (000000000 - 999999999)
3835 3865 int i = t.get(Calendar.MILLISECOND) * 1000000;
3836 3866 Flags flags = Flags.ZERO_PAD;
3837 3867 sb.append(localizedMagnitude(null, i, flags, 9, l));
3838 3868 break;
3839 3869 }
3840 3870 case DateTime.MILLISECOND: { // 'L' (000 - 999)
3841 3871 int i = t.get(Calendar.MILLISECOND);
3842 3872 Flags flags = Flags.ZERO_PAD;
3843 3873 sb.append(localizedMagnitude(null, i, flags, 3, l));
3844 3874 break;
3845 3875 }
3846 3876 case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
3847 3877 long i = t.getTimeInMillis();
3848 3878 Flags flags = Flags.NONE;
3849 3879 sb.append(localizedMagnitude(null, i, flags, width, l));
3850 3880 break;
3851 3881 }
3852 3882 case DateTime.AM_PM: { // 'p' (am or pm)
3853 3883 // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
3854 3884 String[] ampm = { "AM", "PM" };
3855 3885 if (l != null && l != Locale.US) {
3856 3886 DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
3857 3887 ampm = dfs.getAmPmStrings();
3858 3888 }
3859 3889 String s = ampm[t.get(Calendar.AM_PM)];
3860 3890 sb.append(s.toLowerCase(l != null ? l : Locale.US));
3861 3891 break;
3862 3892 }
3863 3893 case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
3864 3894 long i = t.getTimeInMillis() / 1000;
3865 3895 Flags flags = Flags.NONE;
3866 3896 sb.append(localizedMagnitude(null, i, flags, width, l));
3867 3897 break;
3868 3898 }
3869 3899 case DateTime.SECOND: { // 'S' (00 - 60 - leap second)
3870 3900 int i = t.get(Calendar.SECOND);
3871 3901 Flags flags = Flags.ZERO_PAD;
3872 3902 sb.append(localizedMagnitude(null, i, flags, 2, l));
3873 3903 break;
3874 3904 }
3875 3905 case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
3876 3906 int i = t.get(Calendar.ZONE_OFFSET) + t.get(Calendar.DST_OFFSET);
3877 3907 boolean neg = i < 0;
3878 3908 sb.append(neg ? '-' : '+');
3879 3909 if (neg)
3880 3910 i = -i;
3881 3911 int min = i / 60000;
3882 3912 // combine minute and hour into a single integer
3883 3913 int offset = (min / 60) * 100 + (min % 60);
3884 3914 Flags flags = Flags.ZERO_PAD;
3885 3915
3886 3916 sb.append(localizedMagnitude(null, offset, flags, 4, l));
3887 3917 break;
3888 3918 }
3889 3919 case DateTime.ZONE: { // 'Z' (symbol)
3890 3920 TimeZone tz = t.getTimeZone();
3891 3921 sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0),
3892 3922 TimeZone.SHORT,
3893 3923 (l == null) ? Locale.US : l));
3894 3924 break;
3895 3925 }
3896 3926
3897 3927 // Date
3898 3928 case DateTime.NAME_OF_DAY_ABBREV: // 'a'
3899 3929 case DateTime.NAME_OF_DAY: { // 'A'
3900 3930 int i = t.get(Calendar.DAY_OF_WEEK);
3901 3931 Locale lt = ((l == null) ? Locale.US : l);
3902 3932 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
3903 3933 if (c == DateTime.NAME_OF_DAY)
3904 3934 sb.append(dfs.getWeekdays()[i]);
3905 3935 else
3906 3936 sb.append(dfs.getShortWeekdays()[i]);
3907 3937 break;
3908 3938 }
3909 3939 case DateTime.NAME_OF_MONTH_ABBREV: // 'b'
3910 3940 case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
3911 3941 case DateTime.NAME_OF_MONTH: { // 'B'
3912 3942 int i = t.get(Calendar.MONTH);
3913 3943 Locale lt = ((l == null) ? Locale.US : l);
3914 3944 DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
3915 3945 if (c == DateTime.NAME_OF_MONTH)
3916 3946 sb.append(dfs.getMonths()[i]);
3917 3947 else
3918 3948 sb.append(dfs.getShortMonths()[i]);
3919 3949 break;
3920 3950 }
3921 3951 case DateTime.CENTURY: // 'C' (00 - 99)
3922 3952 case DateTime.YEAR_2: // 'y' (00 - 99)
3923 3953 case DateTime.YEAR_4: { // 'Y' (0000 - 9999)
3924 3954 int i = t.get(Calendar.YEAR);
3925 3955 int size = 2;
3926 3956 switch (c) {
3927 3957 case DateTime.CENTURY:
3928 3958 i /= 100;
3929 3959 break;
3930 3960 case DateTime.YEAR_2:
3931 3961 i %= 100;
3932 3962 break;
3933 3963 case DateTime.YEAR_4:
3934 3964 size = 4;
3935 3965 break;
3936 3966 }
3937 3967 Flags flags = Flags.ZERO_PAD;
3938 3968 sb.append(localizedMagnitude(null, i, flags, size, l));
3939 3969 break;
3940 3970 }
3941 3971 case DateTime.DAY_OF_MONTH_0: // 'd' (01 - 31)
3942 3972 case DateTime.DAY_OF_MONTH: { // 'e' (1 - 31) -- like d
3943 3973 int i = t.get(Calendar.DATE);
3944 3974 Flags flags = (c == DateTime.DAY_OF_MONTH_0
3945 3975 ? Flags.ZERO_PAD
3946 3976 : Flags.NONE);
3947 3977 sb.append(localizedMagnitude(null, i, flags, 2, l));
3948 3978 break;
3949 3979 }
3950 3980 case DateTime.DAY_OF_YEAR: { // 'j' (001 - 366)
3951 3981 int i = t.get(Calendar.DAY_OF_YEAR);
3952 3982 Flags flags = Flags.ZERO_PAD;
3953 3983 sb.append(localizedMagnitude(null, i, flags, 3, l));
3954 3984 break;
3955 3985 }
3956 3986 case DateTime.MONTH: { // 'm' (01 - 12)
3957 3987 int i = t.get(Calendar.MONTH) + 1;
3958 3988 Flags flags = Flags.ZERO_PAD;
3959 3989 sb.append(localizedMagnitude(null, i, flags, 2, l));
3960 3990 break;
3961 3991 }
3962 3992
3963 3993 // Composites
3964 3994 case DateTime.TIME: // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
3965 3995 case DateTime.TIME_24_HOUR: { // 'R' (hh:mm same as %H:%M)
3966 3996 char sep = ':';
3967 3997 print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
3968 3998 print(sb, t, DateTime.MINUTE, l);
3969 3999 if (c == DateTime.TIME) {
3970 4000 sb.append(sep);
3971 4001 print(sb, t, DateTime.SECOND, l);
3972 4002 }
3973 4003 break;
3974 4004 }
3975 4005 case DateTime.TIME_12_HOUR: { // 'r' (hh:mm:ss [AP]M)
3976 4006 char sep = ':';
3977 4007 print(sb, t, DateTime.HOUR_0, l).append(sep);
3978 4008 print(sb, t, DateTime.MINUTE, l).append(sep);
3979 4009 print(sb, t, DateTime.SECOND, l).append(' ');
3980 4010 // this may be in wrong place for some locales
3981 4011 StringBuilder tsb = new StringBuilder();
3982 4012 print(tsb, t, DateTime.AM_PM, l);
3983 4013 sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
3984 4014 break;
3985 4015 }
3986 4016 case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999)
3987 4017 char sep = ' ';
3988 4018 print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
3989 4019 print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
3990 4020 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
3991 4021 print(sb, t, DateTime.TIME, l).append(sep);
3992 4022 print(sb, t, DateTime.ZONE, l).append(sep);
3993 4023 print(sb, t, DateTime.YEAR_4, l);
3994 4024 break;
3995 4025 }
3996 4026 case DateTime.DATE: { // 'D' (mm/dd/yy)
3997 4027 char sep = '/';
3998 4028 print(sb, t, DateTime.MONTH, l).append(sep);
3999 4029 print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
4000 4030 print(sb, t, DateTime.YEAR_2, l);
4001 4031 break;
4002 4032 }
4003 4033 case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
4004 4034 char sep = '-';
4005 4035 print(sb, t, DateTime.YEAR_4, l).append(sep);
4006 4036 print(sb, t, DateTime.MONTH, l).append(sep);
4007 4037 print(sb, t, DateTime.DAY_OF_MONTH_0, l);
4008 4038 break;
4009 4039 }
4010 4040 default:
4011 4041 assert false;
4012 4042 }
4013 4043 return sb;
4014 4044 }
4015 4045
4016 4046 // -- Methods to support throwing exceptions --
4017 4047
4018 4048 private void failMismatch(Flags f, char c) {
4019 4049 String fs = f.toString();
4020 4050 throw new FormatFlagsConversionMismatchException(fs, c);
4021 4051 }
4022 4052
4023 4053 private void failConversion(char c, Object arg) {
4024 4054 throw new IllegalFormatConversionException(c, arg.getClass());
4025 4055 }
4026 4056
4027 4057 private char getZero(Locale l) {
4028 4058 if ((l != null) && !l.equals(locale())) {
4029 4059 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
4030 4060 return dfs.getZeroDigit();
4031 4061 }
4032 4062 return zero;
4033 4063 }
4034 4064
4035 4065 private StringBuilder
4036 4066 localizedMagnitude(StringBuilder sb, long value, Flags f,
4037 4067 int width, Locale l)
4038 4068 {
4039 4069 char[] va = Long.toString(value, 10).toCharArray();
4040 4070 return localizedMagnitude(sb, va, f, width, l);
4041 4071 }
4042 4072
4043 4073 private StringBuilder
4044 4074 localizedMagnitude(StringBuilder sb, char[] value, Flags f,
4045 4075 int width, Locale l)
4046 4076 {
4047 4077 if (sb == null)
4048 4078 sb = new StringBuilder();
4049 4079 int begin = sb.length();
4050 4080
4051 4081 char zero = getZero(l);
4052 4082
4053 4083 // determine localized grouping separator and size
4054 4084 char grpSep = '\0';
4055 4085 int grpSize = -1;
4056 4086 char decSep = '\0';
4057 4087
4058 4088 int len = value.length;
4059 4089 int dot = len;
4060 4090 for (int j = 0; j < len; j++) {
4061 4091 if (value[j] == '.') {
4062 4092 dot = j;
4063 4093 break;
4064 4094 }
4065 4095 }
4066 4096
4067 4097 if (dot < len) {
4068 4098 if (l == null || l.equals(Locale.US)) {
4069 4099 decSep = '.';
4070 4100 } else {
4071 4101 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
4072 4102 decSep = dfs.getDecimalSeparator();
4073 4103 }
4074 4104 }
4075 4105
4076 4106 if (f.contains(Flags.GROUP)) {
4077 4107 if (l == null || l.equals(Locale.US)) {
4078 4108 grpSep = ',';
4079 4109 grpSize = 3;
4080 4110 } else {
4081 4111 DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
4082 4112 grpSep = dfs.getGroupingSeparator();
4083 4113 DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
4084 4114 grpSize = df.getGroupingSize();
4085 4115 }
4086 4116 }
4087 4117
4088 4118 // localize the digits inserting group separators as necessary
4089 4119 for (int j = 0; j < len; j++) {
4090 4120 if (j == dot) {
4091 4121 sb.append(decSep);
4092 4122 // no more group separators after the decimal separator
4093 4123 grpSep = '\0';
4094 4124 continue;
4095 4125 }
4096 4126
4097 4127 char c = value[j];
4098 4128 sb.append((char) ((c - '0') + zero));
4099 4129 if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1))
4100 4130 sb.append(grpSep);
4101 4131 }
4102 4132
4103 4133 // apply zero padding
4104 4134 len = sb.length();
4105 4135 if (width != -1 && f.contains(Flags.ZERO_PAD))
4106 4136 for (int k = 0; k < width - len; k++)
4107 4137 sb.insert(begin, zero);
4108 4138
4109 4139 return sb;
4110 4140 }
4111 4141 }
4112 4142
4113 4143 private static class Flags {
4114 4144 private int flags;
4115 4145
4116 4146 static final Flags NONE = new Flags(0); // ''
4117 4147
4118 4148 // duplicate declarations from Formattable.java
4119 4149 static final Flags LEFT_JUSTIFY = new Flags(1<<0); // '-'
4120 4150 static final Flags UPPERCASE = new Flags(1<<1); // '^'
4121 4151 static final Flags ALTERNATE = new Flags(1<<2); // '#'
4122 4152
4123 4153 // numerics
4124 4154 static final Flags PLUS = new Flags(1<<3); // '+'
4125 4155 static final Flags LEADING_SPACE = new Flags(1<<4); // ' '
4126 4156 static final Flags ZERO_PAD = new Flags(1<<5); // '0'
4127 4157 static final Flags GROUP = new Flags(1<<6); // ','
4128 4158 static final Flags PARENTHESES = new Flags(1<<7); // '('
4129 4159
4130 4160 // indexing
4131 4161 static final Flags PREVIOUS = new Flags(1<<8); // '<'
4132 4162
4133 4163 private Flags(int f) {
4134 4164 flags = f;
4135 4165 }
4136 4166
4137 4167 public int valueOf() {
4138 4168 return flags;
4139 4169 }
4140 4170
4141 4171 public boolean contains(Flags f) {
4142 4172 return (flags & f.valueOf()) == f.valueOf();
4143 4173 }
4144 4174
4145 4175 public Flags dup() {
4146 4176 return new Flags(flags);
4147 4177 }
4148 4178
4149 4179 private Flags add(Flags f) {
4150 4180 flags |= f.valueOf();
4151 4181 return this;
4152 4182 }
4153 4183
4154 4184 public Flags remove(Flags f) {
4155 4185 flags &= ~f.valueOf();
4156 4186 return this;
4157 4187 }
4158 4188
4159 4189 public static Flags parse(String s) {
4160 4190 char[] ca = s.toCharArray();
4161 4191 Flags f = new Flags(0);
4162 4192 for (int i = 0; i < ca.length; i++) {
4163 4193 Flags v = parse(ca[i]);
4164 4194 if (f.contains(v))
4165 4195 throw new DuplicateFormatFlagsException(v.toString());
4166 4196 f.add(v);
4167 4197 }
4168 4198 return f;
4169 4199 }
4170 4200
4171 4201 // parse those flags which may be provided by users
4172 4202 private static Flags parse(char c) {
4173 4203 switch (c) {
4174 4204 case '-': return LEFT_JUSTIFY;
4175 4205 case '#': return ALTERNATE;
4176 4206 case '+': return PLUS;
4177 4207 case ' ': return LEADING_SPACE;
4178 4208 case '0': return ZERO_PAD;
4179 4209 case ',': return GROUP;
4180 4210 case '(': return PARENTHESES;
4181 4211 case '<': return PREVIOUS;
4182 4212 default:
4183 4213 throw new UnknownFormatFlagsException(String.valueOf(c));
4184 4214 }
4185 4215 }
4186 4216
4187 4217 // Returns a string representation of the current {@code Flags}.
4188 4218 public static String toString(Flags f) {
4189 4219 return f.toString();
4190 4220 }
4191 4221
4192 4222 public String toString() {
4193 4223 StringBuilder sb = new StringBuilder();
4194 4224 if (contains(LEFT_JUSTIFY)) sb.append('-');
4195 4225 if (contains(UPPERCASE)) sb.append('^');
4196 4226 if (contains(ALTERNATE)) sb.append('#');
4197 4227 if (contains(PLUS)) sb.append('+');
4198 4228 if (contains(LEADING_SPACE)) sb.append(' ');
4199 4229 if (contains(ZERO_PAD)) sb.append('0');
4200 4230 if (contains(GROUP)) sb.append(',');
4201 4231 if (contains(PARENTHESES)) sb.append('(');
4202 4232 if (contains(PREVIOUS)) sb.append('<');
4203 4233 return sb.toString();
4204 4234 }
4205 4235 }
4206 4236
4207 4237 private static class Conversion {
4208 4238 // Byte, Short, Integer, Long, BigInteger
4209 4239 // (and associated primitives due to autoboxing)
4210 4240 static final char DECIMAL_INTEGER = 'd';
4211 4241 static final char OCTAL_INTEGER = 'o';
4212 4242 static final char HEXADECIMAL_INTEGER = 'x';
4213 4243 static final char HEXADECIMAL_INTEGER_UPPER = 'X';
4214 4244
4215 4245 // Float, Double, BigDecimal
4216 4246 // (and associated primitives due to autoboxing)
4217 4247 static final char SCIENTIFIC = 'e';
4218 4248 static final char SCIENTIFIC_UPPER = 'E';
4219 4249 static final char GENERAL = 'g';
4220 4250 static final char GENERAL_UPPER = 'G';
4221 4251 static final char DECIMAL_FLOAT = 'f';
4222 4252 static final char HEXADECIMAL_FLOAT = 'a';
4223 4253 static final char HEXADECIMAL_FLOAT_UPPER = 'A';
4224 4254
4225 4255 // Character, Byte, Short, Integer
4226 4256 // (and associated primitives due to autoboxing)
4227 4257 static final char CHARACTER = 'c';
4228 4258 static final char CHARACTER_UPPER = 'C';
4229 4259
4230 4260 // java.util.Date, java.util.Calendar, long
4231 4261 static final char DATE_TIME = 't';
4232 4262 static final char DATE_TIME_UPPER = 'T';
4233 4263
4234 4264 // if (arg.TYPE != boolean) return boolean
4235 4265 // if (arg != null) return true; else return false;
4236 4266 static final char BOOLEAN = 'b';
4237 4267 static final char BOOLEAN_UPPER = 'B';
4238 4268 // if (arg instanceof Formattable) arg.formatTo()
4239 4269 // else arg.toString();
4240 4270 static final char STRING = 's';
4241 4271 static final char STRING_UPPER = 'S';
4242 4272 // arg.hashCode()
4243 4273 static final char HASHCODE = 'h';
4244 4274 static final char HASHCODE_UPPER = 'H';
4245 4275
4246 4276 static final char LINE_SEPARATOR = 'n';
4247 4277 static final char PERCENT_SIGN = '%';
4248 4278
4249 4279 static boolean isValid(char c) {
4250 4280 return (isGeneral(c) || isInteger(c) || isFloat(c) || isText(c)
4251 4281 || c == 't' || isCharacter(c));
4252 4282 }
4253 4283
4254 4284 // Returns true iff the Conversion is applicable to all objects.
4255 4285 static boolean isGeneral(char c) {
4256 4286 switch (c) {
4257 4287 case BOOLEAN:
4258 4288 case BOOLEAN_UPPER:
4259 4289 case STRING:
4260 4290 case STRING_UPPER:
4261 4291 case HASHCODE:
4262 4292 case HASHCODE_UPPER:
4263 4293 return true;
4264 4294 default:
4265 4295 return false;
4266 4296 }
4267 4297 }
4268 4298
4269 4299 // Returns true iff the Conversion is applicable to character.
4270 4300 static boolean isCharacter(char c) {
4271 4301 switch (c) {
4272 4302 case CHARACTER:
4273 4303 case CHARACTER_UPPER:
4274 4304 return true;
4275 4305 default:
4276 4306 return false;
4277 4307 }
4278 4308 }
4279 4309
4280 4310 // Returns true iff the Conversion is an integer type.
4281 4311 static boolean isInteger(char c) {
4282 4312 switch (c) {
4283 4313 case DECIMAL_INTEGER:
4284 4314 case OCTAL_INTEGER:
4285 4315 case HEXADECIMAL_INTEGER:
4286 4316 case HEXADECIMAL_INTEGER_UPPER:
4287 4317 return true;
4288 4318 default:
4289 4319 return false;
4290 4320 }
4291 4321 }
4292 4322
4293 4323 // Returns true iff the Conversion is a floating-point type.
4294 4324 static boolean isFloat(char c) {
4295 4325 switch (c) {
4296 4326 case SCIENTIFIC:
4297 4327 case SCIENTIFIC_UPPER:
4298 4328 case GENERAL:
4299 4329 case GENERAL_UPPER:
4300 4330 case DECIMAL_FLOAT:
4301 4331 case HEXADECIMAL_FLOAT:
4302 4332 case HEXADECIMAL_FLOAT_UPPER:
4303 4333 return true;
4304 4334 default:
4305 4335 return false;
4306 4336 }
4307 4337 }
4308 4338
4309 4339 // Returns true iff the Conversion does not require an argument
4310 4340 static boolean isText(char c) {
4311 4341 switch (c) {
4312 4342 case LINE_SEPARATOR:
4313 4343 case PERCENT_SIGN:
4314 4344 return true;
4315 4345 default:
4316 4346 return false;
4317 4347 }
4318 4348 }
4319 4349 }
4320 4350
4321 4351 private static class DateTime {
4322 4352 static final char HOUR_OF_DAY_0 = 'H'; // (00 - 23)
4323 4353 static final char HOUR_0 = 'I'; // (01 - 12)
4324 4354 static final char HOUR_OF_DAY = 'k'; // (0 - 23) -- like H
4325 4355 static final char HOUR = 'l'; // (1 - 12) -- like I
4326 4356 static final char MINUTE = 'M'; // (00 - 59)
4327 4357 static final char NANOSECOND = 'N'; // (000000000 - 999999999)
4328 4358 static final char MILLISECOND = 'L'; // jdk, not in gnu (000 - 999)
4329 4359 static final char MILLISECOND_SINCE_EPOCH = 'Q'; // (0 - 99...?)
4330 4360 static final char AM_PM = 'p'; // (am or pm)
4331 4361 static final char SECONDS_SINCE_EPOCH = 's'; // (0 - 99...?)
4332 4362 static final char SECOND = 'S'; // (00 - 60 - leap second)
4333 4363 static final char TIME = 'T'; // (24 hour hh:mm:ss)
4334 4364 static final char ZONE_NUMERIC = 'z'; // (-1200 - +1200) - ls minus?
4335 4365 static final char ZONE = 'Z'; // (symbol)
4336 4366
4337 4367 // Date
4338 4368 static final char NAME_OF_DAY_ABBREV = 'a'; // 'a'
4339 4369 static final char NAME_OF_DAY = 'A'; // 'A'
4340 4370 static final char NAME_OF_MONTH_ABBREV = 'b'; // 'b'
4341 4371 static final char NAME_OF_MONTH = 'B'; // 'B'
4342 4372 static final char CENTURY = 'C'; // (00 - 99)
4343 4373 static final char DAY_OF_MONTH_0 = 'd'; // (01 - 31)
4344 4374 static final char DAY_OF_MONTH = 'e'; // (1 - 31) -- like d
4345 4375 // * static final char ISO_WEEK_OF_YEAR_2 = 'g'; // cross %y %V
4346 4376 // * static final char ISO_WEEK_OF_YEAR_4 = 'G'; // cross %Y %V
4347 4377 static final char NAME_OF_MONTH_ABBREV_X = 'h'; // -- same b
4348 4378 static final char DAY_OF_YEAR = 'j'; // (001 - 366)
4349 4379 static final char MONTH = 'm'; // (01 - 12)
4350 4380 // * static final char DAY_OF_WEEK_1 = 'u'; // (1 - 7) Monday
4351 4381 // * static final char WEEK_OF_YEAR_SUNDAY = 'U'; // (0 - 53) Sunday+
4352 4382 // * static final char WEEK_OF_YEAR_MONDAY_01 = 'V'; // (01 - 53) Monday+
4353 4383 // * static final char DAY_OF_WEEK_0 = 'w'; // (0 - 6) Sunday
4354 4384 // * static final char WEEK_OF_YEAR_MONDAY = 'W'; // (00 - 53) Monday
4355 4385 static final char YEAR_2 = 'y'; // (00 - 99)
4356 4386 static final char YEAR_4 = 'Y'; // (0000 - 9999)
4357 4387
4358 4388 // Composites
4359 4389 static final char TIME_12_HOUR = 'r'; // (hh:mm:ss [AP]M)
4360 4390 static final char TIME_24_HOUR = 'R'; // (hh:mm same as %H:%M)
4361 4391 // * static final char LOCALE_TIME = 'X'; // (%H:%M:%S) - parse format?
4362 4392 static final char DATE_TIME = 'c';
4363 4393 // (Sat Nov 04 12:02:33 EST 1999)
4364 4394 static final char DATE = 'D'; // (mm/dd/yy)
4365 4395 static final char ISO_STANDARD_DATE = 'F'; // (%Y-%m-%d)
4366 4396 // * static final char LOCALE_DATE = 'x'; // (mm/dd/yy)
4367 4397
4368 4398 static boolean isValid(char c) {
4369 4399 switch (c) {
4370 4400 case HOUR_OF_DAY_0:
4371 4401 case HOUR_0:
4372 4402 case HOUR_OF_DAY:
4373 4403 case HOUR:
4374 4404 case MINUTE:
4375 4405 case NANOSECOND:
4376 4406 case MILLISECOND:
4377 4407 case MILLISECOND_SINCE_EPOCH:
4378 4408 case AM_PM:
4379 4409 case SECONDS_SINCE_EPOCH:
4380 4410 case SECOND:
4381 4411 case TIME:
4382 4412 case ZONE_NUMERIC:
4383 4413 case ZONE:
4384 4414
4385 4415 // Date
4386 4416 case NAME_OF_DAY_ABBREV:
4387 4417 case NAME_OF_DAY:
4388 4418 case NAME_OF_MONTH_ABBREV:
4389 4419 case NAME_OF_MONTH:
4390 4420 case CENTURY:
4391 4421 case DAY_OF_MONTH_0:
4392 4422 case DAY_OF_MONTH:
4393 4423 // * case ISO_WEEK_OF_YEAR_2:
4394 4424 // * case ISO_WEEK_OF_YEAR_4:
4395 4425 case NAME_OF_MONTH_ABBREV_X:
4396 4426 case DAY_OF_YEAR:
4397 4427 case MONTH:
4398 4428 // * case DAY_OF_WEEK_1:
4399 4429 // * case WEEK_OF_YEAR_SUNDAY:
4400 4430 // * case WEEK_OF_YEAR_MONDAY_01:
4401 4431 // * case DAY_OF_WEEK_0:
4402 4432 // * case WEEK_OF_YEAR_MONDAY:
4403 4433 case YEAR_2:
4404 4434 case YEAR_4:
4405 4435
4406 4436 // Composites
4407 4437 case TIME_12_HOUR:
4408 4438 case TIME_24_HOUR:
4409 4439 // * case LOCALE_TIME:
4410 4440 case DATE_TIME:
4411 4441 case DATE:
4412 4442 case ISO_STANDARD_DATE:
4413 4443 // * case LOCALE_DATE:
4414 4444 return true;
4415 4445 default:
4416 4446 return false;
4417 4447 }
4418 4448 }
4419 4449 }
4420 4450 }
↓ open down ↓ |
2179 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX