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