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