commit-classpath
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[commit-cp] classpath ChangeLog java/util/Formattable.java ...


From: Andrew John Hughes
Subject: [commit-cp] classpath ChangeLog java/util/Formattable.java ...
Date: Sun, 04 Jun 2006 23:36:27 +0000

CVSROOT:        /cvsroot/classpath
Module name:    classpath
Changes by:     Andrew John Hughes <gnu_andrew> 06/06/04 23:36:27

Modified files:
        .              : ChangeLog 
Added files:
        java/util      : Formattable.java FormattableFlags.java 
                         Formatter.java 

Log message:
        2006-06-04  Andrew John Hughes  <address@hidden>
        
                * java/util/Formattable.java,
                * java/util/FormattableFlags.java,
                * java/util/Formatter.java:
                Documented.
        
        2006-03-20  Andrew John Hughes  <address@hidden>
        
                * java/util/Formatter.java:
                Make the class final.
        
        2005-09-26  Tom Tromey  <address@hidden>
        
                * java/util/Formatter.java (format): Set fmtLocale.
                (applyLocalization): New method.
                (basicIntegralConversion): Likewise.
                (hexOrOctalConversion): Use it.
                (decimalConversion): New method.
                (format): Use decimalConversion, dateTimeConversion.
                (genericFormat): Upper-case earlier.  Justify correctly.
                (singleDateTimeConversion): New method.
                (dateTimeConversion): Likewise.
        
        2005-09-25  Tom Tromey  <address@hidden>
        
                * java/util/Formatter.java (lineSeparator): Use 
SystemProperties.
        
        2005-09-24  Tom Tromey  <address@hidden>
        
                * java/util/FormattableFlags.java (PLUS, SPACE, ZERO, COMMA,
                PAREN): New constants.
                * java/util/Formattable.java: New file.
                * java/util/Formatter.java: New file.
        
        2005-08-13  Tom Tromey  <address@hidden>
        
                * java/util/FormattableFlags.java: New file.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.7651&r2=1.7652
http://cvs.savannah.gnu.org/viewcvs/classpath/java/util/Formattable.java?cvsroot=classpath&rev=1.2
http://cvs.savannah.gnu.org/viewcvs/classpath/java/util/FormattableFlags.java?cvsroot=classpath&rev=1.2
http://cvs.savannah.gnu.org/viewcvs/classpath/java/util/Formatter.java?cvsroot=classpath&rev=1.2

Patches:
Index: ChangeLog
===================================================================
RCS file: /cvsroot/classpath/classpath/ChangeLog,v
retrieving revision 1.7651
retrieving revision 1.7652
diff -u -b -r1.7651 -r1.7652
--- ChangeLog   4 Jun 2006 20:21:39 -0000       1.7651
+++ ChangeLog   4 Jun 2006 23:36:26 -0000       1.7652
@@ -1,3 +1,42 @@
+2006-06-04  Andrew John Hughes  <address@hidden>
+
+       * java/util/Formattable.java,
+       * java/util/FormattableFlags.java,
+       * java/util/Formatter.java:
+       Documented.
+
+2006-03-20  Andrew John Hughes  <address@hidden>
+
+       * java/util/Formatter.java:
+       Make the class final.
+
+2005-09-26  Tom Tromey  <address@hidden>
+
+       * java/util/Formatter.java (format): Set fmtLocale.
+       (applyLocalization): New method.
+       (basicIntegralConversion): Likewise.
+       (hexOrOctalConversion): Use it.
+       (decimalConversion): New method.
+       (format): Use decimalConversion, dateTimeConversion.
+       (genericFormat): Upper-case earlier.  Justify correctly.
+       (singleDateTimeConversion): New method.
+       (dateTimeConversion): Likewise.
+
+2005-09-25  Tom Tromey  <address@hidden>
+
+       * java/util/Formatter.java (lineSeparator): Use SystemProperties.
+
+2005-09-24  Tom Tromey  <address@hidden>
+
+       * java/util/FormattableFlags.java (PLUS, SPACE, ZERO, COMMA,
+       PAREN): New constants.
+       * java/util/Formattable.java: New file.
+       * java/util/Formatter.java: New file.
+
+2005-08-13  Tom Tromey  <address@hidden>
+
+       * java/util/FormattableFlags.java: New file.
+
 2006-06-04  Sven de Marothy  <address@hidden>
 
        * gnu/java/awt/peer/gtk/GtkComponentPeer.java

Index: java/util/Formattable.java
===================================================================
RCS file: java/util/Formattable.java
diff -N java/util/Formattable.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/util/Formattable.java  4 Jun 2006 23:36:27 -0000       1.2
@@ -0,0 +1,92 @@
+/* Formattable.java -- Objects which can be passed to a Formatter
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.util;
+
+/** 
+ * <p>
+ * The <code>Formattable</code> interface is used to provide customised
+ * formatting to arbitrary objects via the address@hidden Formatter}.  The
+ * address@hidden #formatTo} method is called for <code>Formattable</code>
+ * objects used with the 's' conversion operator, allowing the object
+ * to provide its own formatting of its internal data.
+ * </p>
+ * <p>
+ * Thread safety is left up to the implementing class.  Thus,
+ * address@hidden Formattable} objects are not guaranteed to be thread-safe,
+ * and users should make their own provisions for multiple thread access.
+ * </p>
+ *
+ * @author Tom Tromey (address@hidden)
+ * @author Andrew John Hughes (address@hidden)
+ * @since 1.5 
+ */
+public interface Formattable
+{
+
+  /**
+   * Formats the object using the supplied formatter to the specification
+   * provided by the given flags, width and precision.
+   *
+   * @param formatter the formatter to use for formatting the object.
+   *                  The formatter gives access to the output stream
+   *                  and locale via address@hidden Formatter#out()} and
+   *                  address@hidden Formatter#locale()} respectively.
+   * @param flags a bit mask constructed from the flags in the
+   *              address@hidden FormattableFlags} class.  When no flags
+   *              are set, the implementing class should use its
+   *              defaults.
+   * @param width the minimum number of characters to include.
+   *              A value of -1 indicates no minimum.  The remaining
+   *              space is padded with ' ' either on the left
+   *              (the default) or right (if left justification is
+   *              specified by the flags).
+   * @param precision the maximum number of characters to include.
+   *              A value of -1 indicates no maximum.  This value
+   *              is applied prior to the minimum (the width).  Thus,
+   *              a value may meet the minimum width initially, but
+   *              not when the width value is applied, due to
+   *              characters being removed by the precision value.
+   * @throws IllegalFormatException if there is a problem with
+   *                                the syntax of the format
+   *                                specification or a mismatch
+   *                                between it and the arguments.
+   */
+  public void formatTo(Formatter formatter, int flags, int width,
+                      int precision);
+}

Index: java/util/FormattableFlags.java
===================================================================
RCS file: java/util/FormattableFlags.java
diff -N java/util/FormattableFlags.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/util/FormattableFlags.java     4 Jun 2006 23:36:27 -0000       1.2
@@ -0,0 +1,123 @@
+/* FormattableFlags.java --
+   Copyright (C) 2005  Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.util;
+
+/** 
+ * This class contains a set of flags used
+ * by the address@hidden Formattable#formatTo()} method.
+ * They are used to modify the output of the
+ * address@hidden Formattable}.  The interpretation and
+ * validation of the flags is left to the
+ * particular address@hidden Formattable}.
+ *
+ * @author Tom Tromey (address@hidden)
+ * @author Andrew John Hughes (address@hidden)
+ * @since 1.5 
+ */
+public class FormattableFlags
+{
+
+  /**
+   * Requires the output to be left-justified.  Any spaces
+   * required to meet the specified width will be added to
+   * the right of the output.  The default output is
+   * right-justified, where spaces are added to the left.
+   * The output is as for the format specifier
+   * '-' ('\u002d').
+   */
+  public static final int LEFT_JUSTIFY = 1;
+
+  /**
+   * Requires the output to be in uppercase.  The output
+   * should be the same as the result from calling
+   * address@hidden String#toUpperCase(java.util.Locale)} with
+   * the formatting locale. The output is as for the
+   * format specifier '^' ('\u005e').
+   */
+  public static final int UPPERCASE = 2;
+
+  /**
+   * Requires the use of an alternate form, as specified
+   * in the documentation of address@hidden Formattable}.
+   * The output is as for the format specifier
+   * '#' ('\u0023').
+   */
+  public static final int ALTERNATE = 4;
+
+  // Used internally by Formatter.
+  // Changes here must be reflected in the FLAGS string there.
+
+  /**
+   * Requires the output to always include a '+' sign.
+   * The output is as for the format specifier '+'.
+   */
+  static final int PLUS = 8;
+
+  /**
+   * Requires the output to include a leading space on
+   * positive value.  The output is as for the format
+   * specifier ' '.
+   */
+  static final int SPACE = 16;
+
+  /**
+   * Requires the output to be zero-padded.  The output
+   * is as for the format specifier '0'.
+   */
+  static final int ZERO = 32;
+
+  /**
+   * Requires the output to include locale-specific
+   * grouping operators.  The output is as for the
+   * format specifier ','.
+   */
+  static final int COMMA = 64;
+
+  /**
+   * Requires the output to include negative numbers
+   * enclosed in parentheses.  The output is as for
+   * the format specifier '('.
+   */
+  static final int PAREN = 128;
+
+  // Not instantiable.
+  private FormattableFlags()
+  {
+  }
+}

Index: java/util/Formatter.java
===================================================================
RCS file: java/util/Formatter.java
diff -N java/util/Formatter.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ java/util/Formatter.java    4 Jun 2006 23:36:27 -0000       1.2
@@ -0,0 +1,1294 @@
+/* Formatter.java -- printf-style formatting
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.util;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormatSymbols;
+
+import gnu.classpath.SystemProperties;
+
+/** 
+ * <p>
+ * A Java formatter for <code>printf</code>-style format strings,
+ * as seen in the C programming language.   This differs from the
+ * C interpretation of such strings by performing much stricter
+ * checking of format specifications and their corresponding
+ * arguments.  While unknown conversions will be ignored in C,
+ * and invalid conversions will only produce compiler warnings,
+ * the Java version utilises a full range of run-time exceptions to
+ * handle these cases.  The Java version is also more customisable
+ * by virtue of the provision of the address@hidden Formattable} interface,
+ * which allows an arbitrary class to be formatted by the formatter.
+ * </p>
+ * <p>
+ * The formatter is accessible by more convienient static methods.
+ * For example, streams now have appropriate format methods
+ * (the equivalent of <code>fprintf</code>) as do <code>String</code>
+ * objects (the equivalent of <code>sprintf</code>).
+ * </p>
+ * <p>
+ * <strong>Note</strong>: the formatter is not thread-safe.  For
+ * multi-threaded access, external synchronization should be provided.
+ * </p>
+ *  
+ * @author Tom Tromey (address@hidden)
+ * @author Andrew John Hughes (address@hidden)
+ * @since 1.5 
+ */
+public final class Formatter 
+  implements Closeable, Flushable
+{
+
+  /**
+   * The output of the formatter.
+   */
+  private StringBuilder out;
+
+  /**
+   * The locale used by the formatter.
+   */
+  private Locale locale;
+
+  /**
+   * Whether or not the formatter is closed.
+   */
+  private boolean closed;
+
+  /**
+   * The last I/O exception thrown by the output stream.
+   */
+  private IOException ioException;
+
+  // Some state used when actually formatting.
+  /**
+   * The format string.
+   */
+  private String format;
+
+  /**
+   * The current index into the string.
+   */
+  private int index;
+
+  /**
+   * The length of the format string.
+   */
+  private int length;
+
+  /**
+   * The formatting locale.
+   */
+  private Locale fmtLocale;
+
+  // Note that we include '-' twice.  The flags are ordered to
+  // correspond to the values in FormattableFlags, and there is no
+  // flag (in the sense of this field used when parsing) for
+  // UPPERCASE; the second '-' serves as a placeholder.
+  /**
+   * A string used to index into the formattable flags.
+   */
+  private static final String FLAGS = "--#+ 0,(";
+
+  /**
+   * The system line separator.
+   */
+  private static final String lineSeparator
+    = SystemProperties.getProperty("line.separator");
+
+  /**
+   * Constructs a new <code>Formatter</code> using the default
+   * locale and a address@hidden StringBuilder} as the output stream.
+   */
+  public Formatter()
+  {
+    this(null, Locale.getDefault());
+  }
+
+  /**
+   * Constructs a new <code>Formatter</code> using the specified
+   * locale and a address@hidden StringBuilder} as the output stream.
+   * If the locale is <code>null</code>, then no localization
+   * is applied.
+   *
+   * @param loc the locale to use.
+   */
+  public Formatter(Locale loc)
+  {
+    this(null, loc);
+  }
+
+  /**
+   * Constructs a new <code>Formatter</code> using the default
+   * locale and the specified output stream.
+   *
+   * @param app the output stream to use.
+   */
+  public Formatter(StringBuilder app)
+  {
+    this(app, Locale.getDefault());
+  }
+
+  /**
+   * Constructs a new <code>Formatter</code> using the specified
+   * locale and the specified output stream.  If the locale is
+   * <code>null</code>, then no localization is applied.
+   *
+   * @param app the output stream to use.
+   * @param loc the locale to use.
+   */
+  public Formatter(StringBuilder app, Locale loc)
+  {
+    this.out = app == null ? new StringBuilder() : app;
+    this.locale = loc;
+  }
+
+  /**
+   * Closes the formatter, so as to release used resources.
+   * If the underlying output stream supports the address@hidden Closeable}
+   * interface, then this is also closed.  Attempts to use
+   * a formatter instance, via any method other than
+   * address@hidden #ioException()}, after closure results in a
+   * address@hidden FormatterClosedException}.
+   */
+  public void close()
+  {
+    if (closed)
+      return;
+    closed = true;
+  }
+
+  /**
+   * Flushes the formatter, writing any cached data to the output
+   * stream.  If the underlying output stream supports the
+   * address@hidden Flushable} interface, it is also flushed.
+   *
+   * @throws FormatterClosedException if the formatter is closed.
+   */
+  public void flush()
+  {
+    if (closed)
+      throw new FormatterClosedException();
+  }
+
+  /**
+   * Return the name corresponding to a flag.
+   *
+   * @param flags the flag to return the name of.
+   * @return the name of the flag.
+   */
+  private String getName(int flags)
+  {
+    // FIXME: do we want all the flags in here?
+    // Or should we redo how this is reported?
+    int bit = Integer.numberOfTrailingZeros(flags);
+    return FLAGS.substring(bit, bit + 1);
+  }
+
+  /**
+   * Verify the flags passed to a conversion.
+   *
+   * @param flags the flags to verify.
+   * @param allowed the allowed flags mask.
+   * @param conversion the conversion character.
+   */
+  private void checkFlags(int flags, int allowed, char conversion)
+  {
+    flags &= ~allowed;
+    if (flags != 0)
+      throw new FormatFlagsConversionMismatchException(getName(flags),
+                                                      conversion);
+  }
+
+  /**
+   * Throw an exception if a precision was specified.
+   *
+   * @param precision the precision value (-1 indicates not specified).
+   */
+  private void noPrecision(int precision)
+  {
+    if (precision != -1)
+      throw new IllegalFormatPrecisionException(precision);
+  }
+
+  /**
+   * Apply the numeric localization algorithm to a StringBuilder.
+   *
+   * @param builder the builder to apply to.
+   * @param flags the formatting flags to use.
+   * @param width the width of the numeric value.
+   * @param isNegative true if the value is negative.
+   */
+  private void applyLocalization(StringBuilder builder, int flags, int width,
+                                boolean isNegative)
+  {
+    DecimalFormatSymbols dfsyms;
+    if (fmtLocale == null)
+      dfsyms = new DecimalFormatSymbols();
+    else
+      dfsyms = new DecimalFormatSymbols(fmtLocale);
+
+    // First replace each digit.
+    char zeroDigit = dfsyms.getZeroDigit();
+    int decimalOffset = -1;
+    for (int i = builder.length() - 1; i >= 0; --i)
+      {
+       char c = builder.charAt(i);
+       if (c >= '0' && c <= '9')
+         builder.setCharAt(i, (char) (c - '0' + zeroDigit));
+       else if (c == '.')
+         {
+           assert decimalOffset == -1;
+           decimalOffset = i;
+         }
+      }
+
+    // Localize the decimal separator.
+    if (decimalOffset != -1)
+      {
+       builder.deleteCharAt(decimalOffset);
+       builder.insert(decimalOffset, dfsyms.getDecimalSeparator());
+      }
+       
+    // Insert the grouping separators.
+    if ((flags & FormattableFlags.COMMA) != 0)
+      {
+       char groupSeparator = dfsyms.getGroupingSeparator();
+       int groupSize = 3;      // FIXME
+       int offset = (decimalOffset == -1) ? builder.length() : decimalOffset;
+       // We use '>' because we don't want to insert a separator
+       // before the first digit.
+       for (int i = offset - groupSize; i > 0; i -= groupSize)
+         builder.insert(i, groupSeparator);
+      }
+
+    if ((flags & FormattableFlags.ZERO) != 0)
+      {
+       // Zero fill.  Note that according to the algorithm we do not
+       // insert grouping separators here.
+       for (int i = width - builder.length(); i > 0; --i)
+         builder.insert(0, zeroDigit);
+      }
+
+    if (isNegative)
+      {
+       if ((flags & FormattableFlags.PAREN) != 0)
+         {
+           builder.insert(0, '(');
+           builder.append(')');
+         }
+       else
+         builder.insert(0, '-');
+      }
+    else if ((flags & FormattableFlags.PLUS) != 0)
+      builder.insert(0, '+');
+    else if ((flags & FormattableFlags.SPACE) != 0)
+      builder.insert(0, ' ');
+  }
+
+  /**
+   * A helper method that handles emitting a String after applying
+   * precision, width, justification, and upper case flags.
+   *
+   * @param arg the string to emit.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void genericFormat(String arg, int flags, int width, int precision)
+    throws IOException
+  {
+    if ((flags & FormattableFlags.UPPERCASE) != 0)
+      {
+       if (fmtLocale == null)
+         arg = arg.toUpperCase();
+       else
+         arg = arg.toUpperCase(fmtLocale);
+      }
+
+    if (precision >= 0 && arg.length() > precision)
+      arg = arg.substring(0, precision);
+
+    boolean leftJustify = (flags & FormattableFlags.LEFT_JUSTIFY) != 0;
+    if (leftJustify && width == -1)
+      throw new MissingFormatWidthException("fixme");
+    if (! leftJustify && arg.length() < width)
+      {
+       for (int i = width - arg.length(); i > 0; --i)
+         out.append(' ');
+      }
+    out.append(arg);
+    if (leftJustify && arg.length() < width)
+      {
+       for (int i = width - arg.length(); i > 0; --i)
+         out.append(' ');
+      }
+  }
+
+  /** 
+   * Emit a boolean.  
+   *
+   * @param arg the boolean to emit.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param conversion the conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void booleanFormat(Object arg, int flags, int width, int precision,
+                            char conversion)
+    throws IOException
+  {
+    checkFlags(flags,
+              FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
+              conversion);
+    String result;
+    if (arg instanceof Boolean)
+      result = String.valueOf((Boolean) arg);
+    else
+      result = arg == null ? "false" : "true";
+    genericFormat(result, flags, width, precision);
+  }
+
+  /** 
+   * Emit a hash code.  
+   *
+   * @param arg the hash code to emit.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param conversion the conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void hashCodeFormat(Object arg, int flags, int width, int precision,
+                             char conversion)
+    throws IOException
+  {
+    checkFlags(flags,
+              FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
+              conversion);
+    genericFormat(arg == null ? "null" : Integer.toHexString(arg.hashCode()),
+                 flags, width, precision);
+  }
+
+  /** 
+   * Emit a String or Formattable conversion.  
+   *
+   * @param arg the String or Formattable to emit.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param conversion the conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void stringFormat(Object arg, int flags, int width, int precision,
+                           char conversion)
+    throws IOException
+  {
+    if (arg instanceof Formattable)
+      {
+       checkFlags(flags,
+                  (FormattableFlags.LEFT_JUSTIFY
+                   | FormattableFlags.UPPERCASE
+                   | FormattableFlags.ALTERNATE),
+                  conversion);
+       Formattable fmt = (Formattable) arg;
+       fmt.formatTo(this, flags, width, precision);
+      }
+    else
+      {
+       checkFlags(flags,
+                  FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
+                  conversion);
+       genericFormat(arg == null ? "null" : arg.toString(), flags, width,
+                     precision);
+      }
+  }
+
+  /** 
+   * Emit a character.  
+   *
+   * @param arg the character to emit.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param conversion the conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void characterFormat(Object arg, int flags, int width, int precision,
+                              char conversion)
+    throws IOException
+  {
+    checkFlags(flags,
+              FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
+              conversion);
+    noPrecision(precision);
+
+    int theChar;
+    if (arg instanceof Character)
+      theChar = ((Character) arg).charValue();
+    else if (arg instanceof Byte)
+      theChar = (char) (((Byte) arg).byteValue ());
+    else if (arg instanceof Short)
+      theChar = (char) (((Short) arg).shortValue ());
+    else if (arg instanceof Integer)
+      {
+       theChar = ((Integer) arg).intValue();
+       if (! Character.isValidCodePoint(theChar))
+         throw new IllegalFormatCodePointException(theChar);
+      }
+    else
+      throw new IllegalFormatConversionException(conversion, arg.getClass());
+    String result = new String(Character.toChars(theChar));
+    genericFormat(result, flags, width, precision);
+  }
+
+  /** 
+   * Emit a '%'.
+   *
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void percentFormat(int flags, int width, int precision)
+    throws IOException
+  {
+    checkFlags(flags, FormattableFlags.LEFT_JUSTIFY, '%');
+    noPrecision(precision);
+    genericFormat("%", flags, width, precision);
+  }
+
+  /** 
+   * Emit a newline.
+   *
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void newLineFormat(int flags, int width, int precision)
+    throws IOException
+  {
+    checkFlags(flags, 0, 'n');
+    noPrecision(precision);
+    if (width != -1)
+      throw new IllegalFormatWidthException(width);
+    genericFormat(lineSeparator, flags, width, precision);
+  }
+
+  /**
+   * Helper method to do initial formatting and checking for integral
+   * conversions.
+   *
+   * @param arg the formatted argument.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param radix the radix of the number.
+   * @param conversion the conversion character.
+   * @return the result.
+   */
+  private StringBuilder basicIntegralConversion(Object arg, int flags,
+                                               int width, int precision,
+                                               int radix, char conversion)
+  {
+    assert radix == 8 || radix == 10 || radix == 16;
+    noPrecision(precision);
+
+    // Some error checking.
+    if ((flags & FormattableFlags.ZERO) != 0
+       && (flags & FormattableFlags.LEFT_JUSTIFY) == 0)
+      throw new IllegalFormatFlagsException(getName(flags));
+    if ((flags & FormattableFlags.PLUS) != 0
+       && (flags & FormattableFlags.SPACE) != 0)
+      throw new IllegalFormatFlagsException(getName(flags));
+
+    if ((flags & FormattableFlags.LEFT_JUSTIFY) != 0 && width == -1)
+      throw new MissingFormatWidthException("fixme");
+
+    // Do the base translation of the value to a string.
+    String result;
+    int basicFlags = (FormattableFlags.LEFT_JUSTIFY
+                     // We already handled any possible error when
+                     // parsing.
+                     | FormattableFlags.UPPERCASE
+                     | FormattableFlags.ZERO);
+    if (radix == 10)
+      basicFlags |= (FormattableFlags.PLUS
+                    | FormattableFlags.SPACE
+                    | FormattableFlags.COMMA
+                    | FormattableFlags.PAREN);
+    else
+      basicFlags |= FormattableFlags.ALTERNATE;
+
+    if (arg instanceof BigInteger)
+      {
+       checkFlags(flags,
+                  (basicFlags
+                   | FormattableFlags.PLUS
+                   | FormattableFlags.SPACE
+                   | FormattableFlags.PAREN),
+                  conversion);
+       BigInteger bi = (BigInteger) arg;
+       result = bi.toString(radix);
+      }
+    else if (arg instanceof Number
+            && ! (arg instanceof Float)
+            && ! (arg instanceof Double))
+      {
+       checkFlags(flags, basicFlags, conversion);
+       long value = ((Number) arg).longValue ();
+       if (radix == 8)
+         result = Long.toOctalString(value);
+       else if (radix == 16)
+         result = Long.toHexString(value);
+       else
+         result = Long.toString(value);
+      }
+    else
+      throw new IllegalFormatConversionException(conversion, arg.getClass());
+
+    return new StringBuilder(result);
+  }
+
+  /** 
+   * Emit a hex or octal value.  
+   * 
+   * @param arg the hexadecimal or octal value.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param radix the radix of the number.
+   * @param conversion the conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void hexOrOctalConversion(Object arg, int flags, int width,
+                                   int precision, int radix,
+                                   char conversion)
+    throws IOException
+  {
+    assert radix == 8 || radix == 16;
+
+    StringBuilder builder = basicIntegralConversion(arg, flags, width,
+                                                   precision, radix,
+                                                   conversion);
+    int insertPoint = 0;
+
+    // Insert the sign.
+    if (builder.charAt(0) == '-')
+      {
+       // Already inserted.  Note that we don't insert a sign, since
+       // the only case where it is needed it BigInteger, and it has
+       // already been inserted by toString.
+       ++insertPoint;
+      }
+    else if ((flags & FormattableFlags.PLUS) != 0)
+      {
+       builder.insert(insertPoint, '+');
+       ++insertPoint;
+      }
+    else if ((flags & FormattableFlags.SPACE) != 0)
+      {
+       builder.insert(insertPoint, ' ');
+       ++insertPoint;
+      }
+
+    // Insert the radix prefix.
+    if ((flags & FormattableFlags.ALTERNATE) != 0)
+      {
+       builder.insert(insertPoint, radix == 8 ? "0" : "0x");
+       insertPoint += radix == 8 ? 1 : 2;
+      }
+
+    // Now justify the result.
+    int resultWidth = builder.length();
+    if (resultWidth < width)
+      {
+       char fill = ((flags & FormattableFlags.ZERO) != 0) ? '0' : ' ';
+       if ((flags & FormattableFlags.LEFT_JUSTIFY) != 0)
+         {
+           // Left justify.  
+           if (fill == ' ')
+             insertPoint = builder.length();
+         }
+       else
+         {
+           // Right justify.  Insert spaces before the radix prefix
+           // and sign.
+           insertPoint = 0;
+         }
+       while (resultWidth++ < width)
+         builder.insert(insertPoint, fill);
+      }
+
+    String result = builder.toString();
+    if ((flags & FormattableFlags.UPPERCASE) != 0)
+      {
+       if (fmtLocale == null)
+         result = result.toUpperCase();
+       else
+         result = result.toUpperCase(fmtLocale);
+      }
+
+    out.append(result);
+  }
+
+  /** 
+   * Emit a decimal value.  
+   * 
+   * @param arg the hexadecimal or octal value.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param conversion the conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void decimalConversion(Object arg, int flags, int width,
+                                int precision, char conversion)
+    throws IOException
+  {
+    StringBuilder builder = basicIntegralConversion(arg, flags, width,
+                                                   precision, 10,
+                                                   conversion);
+    boolean isNegative = false;
+    if (builder.charAt(0) == '-')
+      {
+       // Sign handling is done during localization.
+       builder.deleteCharAt(0);
+       isNegative = true;
+      }
+
+    applyLocalization(builder, flags, width, isNegative);
+    genericFormat(builder.toString(), flags, width, precision);
+  }
+
+  /** 
+   * Emit a single date or time conversion to a StringBuilder.  
+   *
+   * @param builder the builder to write to.
+   * @param cal the calendar to use in the conversion.
+   * @param conversion the formatting character to specify the type of data.
+   * @param syms the date formatting symbols.
+   */
+  private void singleDateTimeConversion(StringBuilder builder, Calendar cal,
+                                       char conversion,
+                                       DateFormatSymbols syms)
+  {
+    int oldLen = builder.length();
+    int digits = -1;
+    switch (conversion)
+      {
+      case 'H':
+       builder.append(cal.get(Calendar.HOUR_OF_DAY));
+       digits = 2;
+       break;
+      case 'I':
+       builder.append(cal.get(Calendar.HOUR));
+       digits = 2;
+       break;
+      case 'k':
+       builder.append(cal.get(Calendar.HOUR_OF_DAY));
+       break;
+      case 'l':
+       builder.append(cal.get(Calendar.HOUR));
+       break;
+      case 'M':
+       builder.append(cal.get(Calendar.MINUTE));
+       digits = 2;
+       break;
+      case 'S':
+       builder.append(cal.get(Calendar.SECOND));
+       digits = 2;
+       break;
+      case 'N':
+       // FIXME: nanosecond ...
+       digits = 9;
+       break;
+      case 'p':
+       {
+         int ampm = cal.get(Calendar.AM_PM);
+         builder.append(syms.getAmPmStrings()[ampm]);
+       }
+       break;
+      case 'z':
+       {
+         int zone = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60);
+         builder.append(zone);
+         digits = 4;
+         // Skip the '-' sign.
+         if (zone < 0)
+           ++oldLen;
+       }
+       break;
+      case 'Z':
+       {
+         // FIXME: DST?
+         int zone = cal.get(Calendar.ZONE_OFFSET) / (1000 * 60 * 60);
+         String[][] zs = syms.getZoneStrings();
+         builder.append(zs[zone + 12][1]);
+       }
+       break;
+      case 's':
+       {
+         long val = cal.getTime().getTime();
+         builder.append(val / 1000);
+       }
+       break;
+      case 'Q':
+       {
+         long val = cal.getTime().getTime();
+         builder.append(val);
+       }
+       break;
+      case 'B':
+       {
+         int month = cal.get(Calendar.MONTH);
+         builder.append(syms.getMonths()[month]);
+       }
+       break;
+      case 'b':
+      case 'h':
+       {
+         int month = cal.get(Calendar.MONTH);
+         builder.append(syms.getShortMonths()[month]);
+       }
+       break;
+      case 'A':
+       {
+         int day = cal.get(Calendar.DAY_OF_WEEK);
+         builder.append(syms.getWeekdays()[day]);
+       }
+       break;
+      case 'a':
+       {
+         int day = cal.get(Calendar.DAY_OF_WEEK);
+         builder.append(syms.getShortWeekdays()[day]);
+       }
+       break;
+      case 'C':
+       builder.append(cal.get(Calendar.YEAR) / 100);
+       digits = 2;
+       break;
+      case 'Y':
+       builder.append(cal.get(Calendar.YEAR));
+       digits = 4;
+       break;
+      case 'y':
+       builder.append(cal.get(Calendar.YEAR) % 100);
+       digits = 2;
+       break;
+      case 'j':
+       builder.append(cal.get(Calendar.DAY_OF_YEAR));
+       digits = 3;
+       break;
+      case 'm':
+       builder.append(cal.get(Calendar.MONTH) + 1);
+       digits = 2;
+       break;
+      case 'd':
+       builder.append(cal.get(Calendar.DAY_OF_MONTH));
+       digits = 2;
+       break;
+      case 'e':
+       builder.append(cal.get(Calendar.DAY_OF_MONTH));
+       break;
+      case 'R':
+       singleDateTimeConversion(builder, cal, 'H', syms);
+       builder.append(':');
+       singleDateTimeConversion(builder, cal, 'M', syms);
+       break;
+      case 'T':
+       singleDateTimeConversion(builder, cal, 'H', syms);
+       builder.append(':');
+       singleDateTimeConversion(builder, cal, 'M', syms);
+       builder.append(':');
+       singleDateTimeConversion(builder, cal, 'S', syms);
+       break;
+      case 'r':
+       singleDateTimeConversion(builder, cal, 'I', syms);
+       builder.append(':');
+       singleDateTimeConversion(builder, cal, 'M', syms);
+       builder.append(':');
+       singleDateTimeConversion(builder, cal, 'S', syms);
+       builder.append(' ');
+       singleDateTimeConversion(builder, cal, 'p', syms);
+       break;
+      case 'D':
+       singleDateTimeConversion(builder, cal, 'm', syms);
+       builder.append('/');
+       singleDateTimeConversion(builder, cal, 'd', syms);
+       builder.append('/');
+       singleDateTimeConversion(builder, cal, 'y', syms);
+       break;
+      case 'F':
+       singleDateTimeConversion(builder, cal, 'Y', syms);
+       builder.append('-');
+       singleDateTimeConversion(builder, cal, 'm', syms);
+       builder.append('-');
+       singleDateTimeConversion(builder, cal, 'd', syms);
+       break;
+      case 'c':
+       singleDateTimeConversion(builder, cal, 'a', syms);
+       builder.append(' ');
+       singleDateTimeConversion(builder, cal, 'b', syms);
+       builder.append(' ');
+       singleDateTimeConversion(builder, cal, 'd', syms);
+       builder.append(' ');
+       singleDateTimeConversion(builder, cal, 'T', syms);
+       builder.append(' ');
+       singleDateTimeConversion(builder, cal, 'Z', syms);
+       builder.append(' ');
+       singleDateTimeConversion(builder, cal, 'Y', syms);
+       break;
+      default:
+       throw new UnknownFormatConversionException(String.valueOf(conversion));
+      }
+
+    if (digits > 0)
+      {
+       int newLen = builder.length();
+       int delta = newLen - oldLen;
+       while (delta++ < digits)
+         builder.insert(oldLen, '0');
+      }
+  }
+
+  /**
+   * Emit a date or time value.
+   *
+   * @param arg the date or time value.
+   * @param flags the formatting flags to use.
+   * @param width the width to use.
+   * @param precision the precision to use.
+   * @param conversion the conversion character.
+   * @param subConversion the sub conversion character.
+   * @throws IOException if the output stream throws an I/O error.
+   */
+  private void dateTimeConversion(Object arg, int flags, int width,
+                                 int precision, char conversion,
+                                 char subConversion)
+    throws IOException
+  {
+    noPrecision(precision);
+    checkFlags(flags,
+              FormattableFlags.LEFT_JUSTIFY | FormattableFlags.UPPERCASE,
+              conversion);
+
+    Calendar cal;
+    if (arg instanceof Calendar)
+      cal = (Calendar) arg;
+    else
+      {
+       Date date;
+       if (arg instanceof Date)
+         date = (Date) arg;
+       else if (arg instanceof Long)
+         date = new Date(((Long) arg).longValue());
+       else
+         throw new IllegalFormatConversionException(conversion,
+                                                    arg.getClass());
+       if (fmtLocale == null)
+         cal = Calendar.getInstance();
+       else
+         cal = Calendar.getInstance(fmtLocale);
+       cal.setTime(date);
+      }
+
+    // We could try to be more efficient by computing this lazily.
+    DateFormatSymbols syms;
+    if (fmtLocale == null)
+      syms = new DateFormatSymbols();
+    else
+      syms = new DateFormatSymbols(fmtLocale);
+
+    StringBuilder result = new StringBuilder();
+    singleDateTimeConversion(result, cal, subConversion, syms);
+
+    genericFormat(result.toString(), flags, width, precision);
+  }
+
+  /**
+   * Advance the internal parsing index, and throw an exception
+   * on overrun.
+   *
+   * @throws IllegalArgumentException on overrun.
+   */
+  private void advance()
+  {
+    ++index;
+    if (index >= length)
+      {
+       // FIXME: what exception here?
+       throw new IllegalArgumentException();
+      }
+  }
+
+  /**
+   * Parse an integer appearing in the format string.  Will return -1
+   * if no integer was found.
+   *
+   * @return the parsed integer.
+   */
+  private int parseInt()
+  {
+    int start = index;
+    while (Character.isDigit(format.charAt(index)))
+      advance();
+    if (start == index)
+      return -1;
+    return Integer.decode(format.substring(start, index)).intValue();
+  }
+
+  /**
+   * Parse the argument index.  Returns -1 if there was no index, 0 if
+   * we should re-use the previous index, and a positive integer to
+   * indicate an absolute index.
+   *
+   * @return the parsed argument index.
+   */
+  private int parseArgumentIndex()
+  {
+    int result = -1;
+    int start = index;
+    if (format.charAt(index) == '<')
+      {
+       result = 0;
+       advance();
+      }
+    else if (Character.isDigit(format.charAt(index)))
+      {
+       result = parseInt();
+       if (format.charAt(index) == '$')
+         advance();
+       else
+         {
+           // Reset.
+           index = start;
+           result = -1;
+         }
+      }
+    return result;
+  }
+
+  /**
+   * Parse a set of flags and return a bit mask of values from
+   * FormattableFlags.  Will throw an exception if a flag is
+   * duplicated.
+   *
+   * @return the parsed flags.
+   */
+  private int parseFlags()
+  {
+    int value = 0;
+    int start = index;
+    while (true)
+      {
+       int x = FLAGS.indexOf(format.charAt(index));
+       if (x == -1)
+         break;
+       int newValue = 1 << x;
+       if ((value & newValue) != 0)
+         throw new DuplicateFormatFlagsException(format.substring(start,
+                                                                  index + 1));
+       value |= newValue;
+       advance();
+      }
+    return value;
+  }
+
+  /**
+   * Parse the width part of a format string.  Returns -1 if no width
+   * was specified.
+   *
+   * @return the parsed width.
+   */
+  private int parseWidth()
+  {
+    return parseInt();
+  }
+
+  /**
+   * If the current character is '.', parses the precision part of a
+   * format string.  Returns -1 if no precision was specified.
+   *
+   * @return the parsed precision.
+   */
+  private int parsePrecision()
+  {
+    if (format.charAt(index) != '.')
+      return -1;
+    advance();
+    int precision = parseInt();
+    if (precision == -1)
+      // FIXME
+      throw new IllegalArgumentException();
+    return precision;
+  }
+
+  /**
+   * Outputs a formatted string based on the supplied specification,
+   * <code>fmt</code>, and its arguments using the specified locale.
+   * The locale of the formatter does not change as a result; the
+   * specified locale is just used for this particular formatting
+   * operation.  If the locale is <code>null</code>, then no
+   * localization is applied.
+   *
+   * @param loc the locale to use for this format.
+   * @param fmt the format specification.
+   * @param args the arguments to apply to the specification.
+   * @throws IllegalFormatException if there is a problem with
+   *                                the syntax of the format
+   *                                specification or a mismatch
+   *                                between it and the arguments.
+   * @throws FormatterClosedException if the formatter is closed.
+   */ 
+  public Formatter format(Locale loc, String fmt, Object[] args)
+  {
+    if (closed)
+      throw new FormatterClosedException();
+
+    // Note the arguments are indexed starting at 1.
+    int implicitArgumentIndex = 1;
+    int previousArgumentIndex = 0;
+
+    try
+      {
+       fmtLocale = loc;
+       format = fmt;
+       length = format.length();
+       for (index = 0; index < length; ++index)
+         {
+           char c = format.charAt(index);
+           if (c != '%')
+             {
+               out.append(c);
+               continue;
+             }
+
+           int start = index;
+           advance();
+
+           // We do the needed post-processing of this later, when we
+           // determine whether an argument is actually needed by
+           // this conversion.
+           int argumentIndex = parseArgumentIndex();
+
+           int flags = parseFlags();
+           int width = parseWidth();
+           int precision = parsePrecision();
+           char origConversion = format.charAt(index);
+           char conversion = origConversion;
+           if (Character.isUpperCase(conversion))
+             {
+               flags |= FormattableFlags.UPPERCASE;
+               conversion = Character.toLowerCase(conversion);
+             }
+
+           Object argument = null;
+           if (conversion == '%' || conversion == 'n')
+             {
+               if (argumentIndex != -1)
+                 {
+                   // FIXME: not sure about this.
+                   throw new UnknownFormatConversionException("FIXME");
+                 }
+             }
+           else
+             {
+               if (argumentIndex == -1)
+                 argumentIndex = implicitArgumentIndex++;
+               else if (argumentIndex == 0)
+                 argumentIndex = previousArgumentIndex;
+               // Argument indices start at 1 but array indices at 0.
+               --argumentIndex;
+               if (argumentIndex < 0 || argumentIndex >= args.length)
+                 throw new 
MissingFormatArgumentException(format.substring(start, index));
+               argument = args[argumentIndex];
+             }
+
+           switch (conversion)
+             {
+             case 'b':
+               booleanFormat(argument, flags, width, precision,
+                             origConversion);
+               break;
+             case 'h':
+               hashCodeFormat(argument, flags, width, precision,
+                              origConversion);
+               break;
+             case 's':
+               stringFormat(argument, flags, width, precision,
+                            origConversion);
+               break;
+             case 'c':
+               characterFormat(argument, flags, width, precision,
+                               origConversion);
+               break;
+             case 'd':
+               checkFlags(flags & FormattableFlags.UPPERCASE, 0, 'd');
+               decimalConversion(argument, flags, width, precision,
+                                 origConversion);
+               break;
+             case 'o':
+               checkFlags(flags & FormattableFlags.UPPERCASE, 0, 'o');
+               hexOrOctalConversion(argument, flags, width, precision, 8,
+                                    origConversion);
+               break;
+             case 'x':
+               hexOrOctalConversion(argument, flags, width, precision, 16,
+                                    origConversion);
+             case 'e':
+               // scientificNotationConversion();
+               break;
+             case 'f':
+               // floatingDecimalConversion();
+               break;
+             case 'g':
+               // smartFloatingConversion();
+               break;
+             case 'a':
+               // hexFloatingConversion();
+               break;
+             case 't':
+               advance();
+               char subConversion = format.charAt(index);
+               dateTimeConversion(argument, flags, width, precision,
+                                  origConversion, subConversion);
+               break;
+             case '%':
+               percentFormat(flags, width, precision);
+               break;
+             case 'n':
+               newLineFormat(flags, width, precision);
+               break;
+             default:
+               throw new 
UnknownFormatConversionException(String.valueOf(origConversion));
+             }
+         }
+      }
+    catch (IOException exc)
+      {
+       ioException = exc;
+      }
+    return this;
+  }
+
+  /**
+   * Outputs a formatted string based on the supplied specification,
+   * <code>fmt</code>, and its arguments using the formatter's locale.
+   *
+   * @param fmt the format specification.
+   * @param args the arguments to apply to the specification.
+   * @throws IllegalFormatException if there is a problem with
+   *                                the syntax of the format
+   *                                specification or a mismatch
+   *                                between it and the arguments.
+   * @throws FormatterClosedException if the formatter is closed.
+   */
+  public Formatter format(String format, Object[] args)
+  {
+    return format(locale, format, args);
+  }
+
+  /**
+   * Returns the last I/O exception thrown by the
+   * <code>append()</code> operation of the underlying
+   * output stream.
+   *
+   * @return the last I/O exception.
+   */
+  public IOException ioException()
+  {
+    return ioException;
+  }
+
+  /**
+   * Returns the locale used by this formatter.
+   *
+   * @return the formatter's locale.
+   * @throws FormatterClosedException if the formatter is closed.
+   */
+  public Locale locale()
+  {
+    if (closed)
+      throw new FormatterClosedException();
+    return locale;
+  }
+
+  /**
+   * Returns the output stream used by this formatter.
+   *
+   * @return the formatter's output stream.
+   * @throws FormatterClosedException if the formatter is closed.
+   */
+  public StringBuilder out()
+  {
+    if (closed)
+      throw new FormatterClosedException();
+    return out;
+  }
+
+  /**
+   * Returns the result of applying address@hidden Object#toString()}
+   * to the underlying output stream.  The results returned
+   * depend on the particular address@hidden Appendable} being used.
+   * For example, a address@hidden StringBuilder} will return the
+   * formatted output but an I/O stream will not.
+   *
+   * @throws FormatterClosedException if the formatter is closed.
+   */
+  public String toString()
+  {
+    if (closed)
+      throw new FormatterClosedException();
+    return out.toString();
+  }
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]