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