IndentingWriter.java revision 7e58d497ef4ff49f9cc11930ae3d9fb3fc191346
11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci/*
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * [The "BSD licence"]
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Copyright (c) 2010 Ben Gruver
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * All rights reserved.
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * Redistribution and use in source and binary forms, with or without
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * modification, are permitted provided that the following conditions
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * are met:
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 1. Redistributions of source code must retain the above copyright
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *    notice, this list of conditions and the following disclaimer.
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 2. Redistributions in binary form must reproduce the above copyright
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *    notice, this list of conditions and the following disclaimer in the
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *    documentation and/or other materials provided with the distribution.
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * 3. The name of the author may not be used to endorse or promote products
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *    derived from this software without specific prior written permission.
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci *
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci */
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipackage org.jf.util;
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.io.IOException;
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport java.io.Writer;
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// TODO: add a write(String) method that doesn't scan for embedded newlines?
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccipublic class IndentingWriter extends Writer {
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    protected final Writer writer;
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    protected final char[] buffer = new char[16];
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    protected int indentLevel = 0;
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private boolean beginningOfLine = true;
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private static final String newLine = System.getProperty("line.separator");
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public IndentingWriter(Writer writer) {
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        this.writer = writer;
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    protected void writeIndent() throws IOException {
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        for (int i=0; i<indentLevel; i++) {
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            writer.write(' ');
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @Override
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public void write(int chr) throws IOException {
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (chr == '\n') {
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            writer.write(newLine);
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            beginningOfLine = true;
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        } else {
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            if (beginningOfLine) {
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                writeIndent();
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            }
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            beginningOfLine = false;
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            writer.write(chr);
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Writes out a block of text that contains no newlines
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private void writeLine(char[] chars, int start, int len) throws IOException {
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (beginningOfLine && len > 0) {
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            writeIndent();
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            beginningOfLine = false;
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        writer.write(chars, start, len);
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Writes out a block of text that contains no newlines
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    private void writeLine(String str, int start, int len) throws IOException {
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        if (beginningOfLine && len > 0) {
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            writeIndent();
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            beginningOfLine = false;
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        }
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        writer.write(str, start, len);
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @Override
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public void write(char[] chars) throws IOException {
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        write(chars, 0, chars.length);
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    @Override
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    public void write(char[] chars, int start, int len) throws IOException {
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        final int end = start+len;
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        int pos = start;
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        while (pos < end) {
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            if (chars[pos] == '\n') {
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                writeLine(chars, start, pos-start);
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
102                writer.write(newLine);
103                beginningOfLine = true;
104                pos++;
105                start = pos;
106            } else {
107                pos++;
108            }
109        }
110        writeLine(chars, start, pos-start);
111    }
112
113    @Override
114    public void write(String s) throws IOException {
115        write(s, 0, s.length());
116    }
117
118    @Override
119    public void write(String str, int start, int len) throws IOException {
120        final int end = start+len;
121        int pos = start;
122        while (pos < end) {
123            pos = str.indexOf('\n', start);
124            if (pos == -1) {
125                writeLine(str, start, end-start);
126                return;
127            } else {
128                writeLine(str, start, pos-start);
129                writer.write(newLine);
130                beginningOfLine = true;
131                start = pos+1;
132            }
133        }
134    }
135
136    @Override
137    public Writer append(CharSequence charSequence) throws IOException {
138        write(charSequence.toString());
139        return this;
140    }
141
142    @Override
143    public Writer append(CharSequence charSequence, int start, int len) throws IOException {
144        write(charSequence.subSequence(start, len).toString());
145        return this;
146    }
147
148    @Override
149    public Writer append(char c) throws IOException {
150        write(c);
151        return this;
152    }
153
154    @Override
155    public void flush() throws IOException {
156        writer.flush();
157    }
158
159    @Override
160    public void close() throws IOException {
161        writer.close();
162    }
163
164    public void indent(int indentAmount) {
165        this.indentLevel += indentAmount;
166        if (indentLevel < 0) {
167            indentLevel = 0;
168        }
169    }
170
171    public void deindent(int indentAmount) {
172        this.indentLevel -= indentAmount;
173        if (indentLevel < 0) {
174            indentLevel = 0;
175        }
176    }
177
178    public void printUnsignedLongAsHex(long value) throws IOException {
179        int bufferIndex = 0;
180        do {
181            int digit = (int)(value & 15);
182            if (digit < 10) {
183                buffer[bufferIndex++] = (char)(digit + '0');
184            } else {
185                buffer[bufferIndex++] = (char)((digit - 10) + 'a');
186            }
187
188            value >>>= 4;
189        } while (value != 0);
190
191        writeLine(buffer, 0, bufferIndex);
192    }
193
194    public void printSignedIntAsDec(int value) throws IOException {
195        int bufferIndex = 0;
196
197        if (value < 0) {
198            value *= -1;
199            write('-');
200        }
201
202        do {
203            int digit = value % 10;
204            buffer[bufferIndex++] = (char)(digit + '0');
205
206            value = value / 10;
207        } while (value != 0);
208
209        writeLine(buffer, 0, bufferIndex);
210    }
211}
212