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