| 1 | package net.sourceforge.retroweaver.runtime.java.util; |
| 2 | |
| 3 | import java.util.Locale; |
| 4 | import java.lang.reflect.Method; |
| 5 | import java.lang.reflect.InvocationTargetException; |
| 6 | import java.io.IOException; |
| 7 | |
| 8 | public class Formatter { |
| 9 | |
| 10 | public Formatter() { this(new StringBuilder(), Locale.getDefault()); } |
| 11 | |
| 12 | public Formatter(Appendable a) { this(a, Locale.getDefault()); } |
| 13 | |
| 14 | public Formatter(Locale l) { this(new StringBuilder(), l); } |
| 15 | |
| 16 | public Formatter(Appendable a, Locale l) { |
| 17 | buffer = a == null?new StringBuilder():a; |
| 18 | |
| 19 | try { |
| 20 | appendMethod = buffer.getClass().getMethod("append", new Class[] { String.class }); |
| 21 | } catch (NoSuchMethodException e) { |
| 22 | throw new RuntimeException(e); |
| 23 | } |
| 24 | locale = l; |
| 25 | } |
| 26 | |
| 27 | private Appendable buffer; |
| 28 | |
| 29 | private Method appendMethod; |
| 30 | |
| 31 | private Locale locale; |
| 32 | |
| 33 | private boolean closed; |
| 34 | |
| 35 | private IOException ioe; |
| 36 | |
| 37 | public Locale locale() { |
| 38 | if (closed) { |
| 39 | throw new FormatterClosedException(); |
| 40 | } |
| 41 | return locale; |
| 42 | } |
| 43 | |
| 44 | public Appendable out() { |
| 45 | if (closed) { |
| 46 | throw new FormatterClosedException(); |
| 47 | } |
| 48 | return buffer; |
| 49 | } |
| 50 | |
| 51 | public String toString() { |
| 52 | if (closed) { |
| 53 | throw new FormatterClosedException(); |
| 54 | } |
| 55 | return buffer.toString(); |
| 56 | } |
| 57 | |
| 58 | public void flush() { |
| 59 | if (closed) { |
| 60 | throw new FormatterClosedException(); |
| 61 | } |
| 62 | |
| 63 | // Flushable is 1.5+ |
| 64 | try { |
| 65 | Method m = buffer.getClass().getMethod("flush", new Class<?>[0]); |
| 66 | m.invoke(buffer, new Object[0]); |
| 67 | } catch (Exception e) { |
| 68 | // ignored; |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | public void close() { |
| 73 | if (!closed) { |
| 74 | closed = true; |
| 75 | |
| 76 | // Closeable is 1.5+ |
| 77 | try { |
| 78 | Method m = buffer.getClass().getMethod("close", new Class<?>[0]); |
| 79 | m.invoke(buffer, new Object[0]); |
| 80 | } catch (Exception e) { |
| 81 | // ignored; |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | public IOException ioException() { |
| 87 | return ioe; |
| 88 | } |
| 89 | |
| 90 | public Formatter format(String format, Object... args) throws IllegalFormatException, FormatterClosedException { |
| 91 | return format(locale, format, args); |
| 92 | } |
| 93 | |
| 94 | public Formatter format(Locale l, String format, Object... args) throws IllegalFormatException, FormatterClosedException { |
| 95 | if (closed) { |
| 96 | throw new FormatterClosedException(); |
| 97 | } |
| 98 | |
| 99 | //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 | |