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