001 package net.sourceforge.retroweaver.runtime.java.util;
002
003 import java.util.Locale;
004 import java.lang.reflect.Method;
005 import java.lang.reflect.InvocationTargetException;
006 import java.io.IOException;
007
008 public class Formatter {
009
010 public Formatter() { this(new StringBuilder(), Locale.getDefault()); }
011
012 public Formatter(Appendable a) { this(a, Locale.getDefault()); }
013
014 public Formatter(Locale l) { this(new StringBuilder(), l); }
015
016 public Formatter(Appendable a, Locale l) {
017 buffer = a == null?new StringBuilder():a;
018
019 try {
020 appendMethod = buffer.getClass().getMethod("append", new Class[] { String.class });
021 } catch (NoSuchMethodException e) {
022 throw new RuntimeException(e);
023 }
024 locale = l;
025 }
026
027 private Appendable buffer;
028
029 private Method appendMethod;
030
031 private Locale locale;
032
033 private boolean closed;
034
035 private IOException ioe;
036
037 public Locale locale() {
038 if (closed) {
039 throw new FormatterClosedException();
040 }
041 return locale;
042 }
043
044 public Appendable out() {
045 if (closed) {
046 throw new FormatterClosedException();
047 }
048 return buffer;
049 }
050
051 public String toString() {
052 if (closed) {
053 throw new FormatterClosedException();
054 }
055 return buffer.toString();
056 }
057
058 public void flush() {
059 if (closed) {
060 throw new FormatterClosedException();
061 }
062
063 // Flushable is 1.5+
064 try {
065 Method m = buffer.getClass().getMethod("flush", new Class<?>[0]);
066 m.invoke(buffer, new Object[0]);
067 } catch (Exception e) {
068 // ignored;
069 }
070 }
071
072 public void close() {
073 if (!closed) {
074 closed = true;
075
076 // Closeable is 1.5+
077 try {
078 Method m = buffer.getClass().getMethod("close", new Class<?>[0]);
079 m.invoke(buffer, new Object[0]);
080 } catch (Exception e) {
081 // ignored;
082 }
083 }
084 }
085
086 public IOException ioException() {
087 return ioe;
088 }
089
090 public Formatter format(String format, Object... args) throws IllegalFormatException, FormatterClosedException {
091 return format(locale, format, args);
092 }
093
094 public Formatter format(Locale l, String format, Object... args) throws IllegalFormatException, FormatterClosedException {
095 if (closed) {
096 throw new FormatterClosedException();
097 }
098
099 //System.err.println("Format: " + format + ' ' + args.length);
100 //for (Object a: args) System.err.println("\t" + a.getClass() + ": " + a);
101
102 int start = 0;
103 int end;
104 int argIndex = 0;
105
106 while (true) {
107 try {
108 end = format.indexOf('%', start);
109 if (end == -1) {
110 append(format.substring(start, format.length()));
111 break;
112 }
113 append(format.substring(start, end));
114 if (end == format.length()) {
115 throw new IllegalFormatException();
116 }
117 char c = format.charAt(end+1);
118 switch (c) {
119 case '%':
120 append("%");
121 break;
122 case 's':
123 Object o = args[argIndex++];
124 append(o==null?null:o.toString());
125 break;
126 case 'd':
127 o = args[argIndex++];
128 append(o.toString());
129 break;
130 default:
131 throw new IllegalFormatException();
132 }
133 start = end + 2;
134 } catch (IOException ioe) {
135 this.ioe = ioe;
136 }
137 }
138
139 return this;
140 }
141
142 private void append(String s) throws IOException {
143 try {
144 appendMethod.invoke(buffer, s);
145 } catch (InvocationTargetException ite) {
146 if (ite.getCause() instanceof IOException) {
147 throw (IOException) ite.getCause();
148 }
149 } catch (Exception e) {
150 throw new RuntimeException(e);
151 }
152 }
153
154 }
155