IndentingWriter.java revision d9c50f3f36b1cc8c3d54426f9022fb638ae6cc8d
1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2010 Ben Gruver
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29package org.jf.util;
30
31import java.io.IOException;
32import java.io.Writer;
33
34// TODO: add a write(String) method that doesn't scan for embedded newlines?
35public class IndentingWriter extends Writer {
36    protected final Writer writer;
37    protected final char[] buffer = new char[24];
38    protected int indentLevel = 0;
39    private boolean beginningOfLine = true;
40    private static final String newLine = System.getProperty("line.separator");
41
42    public IndentingWriter(Writer writer) {
43        this.writer = writer;
44    }
45
46    protected void writeIndent() throws IOException {
47        for (int i=0; i<indentLevel; i++) {
48            writer.write(' ');
49        }
50    }
51
52    @Override
53    public void write(int chr) throws IOException {
54        if (chr == '\n') {
55            writer.write(newLine);
56            beginningOfLine = true;
57        } else {
58            if (beginningOfLine) {
59                writeIndent();
60            }
61            beginningOfLine = false;
62            writer.write(chr);
63        }
64    }
65
66    /**
67     * Writes out a block of text that contains no newlines
68     */
69    private void writeLine(char[] chars, int start, int len) throws IOException {
70        if (beginningOfLine && len > 0) {
71            writeIndent();
72            beginningOfLine = false;
73        }
74        writer.write(chars, start, len);
75    }
76
77
78    /**
79     * Writes out a block of text that contains no newlines
80     */
81    private void writeLine(String str, int start, int len) throws IOException {
82        if (beginningOfLine && len > 0) {
83            writeIndent();
84            beginningOfLine = false;
85        }
86        writer.write(str, start, len);
87    }
88
89    @Override
90    public void write(char[] chars) throws IOException {
91        write(chars, 0, chars.length);
92    }
93
94    @Override
95    public void write(char[] chars, int start, int len) throws IOException {
96        final int end = start+len;
97        int pos = start;
98        while (pos < end) {
99            if (chars[pos] == '\n') {
100                writeLine(chars, start, pos-start);
101
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 = 23;
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        bufferIndex++;
192
193        writeLine(buffer, bufferIndex, 24-bufferIndex);
194    }
195
196    public void printSignedIntAsDec(int value) throws IOException {
197        int bufferIndex = 15;
198
199        if (value < 0) {
200            value *= -1;
201            write('-');
202        }
203
204        do {
205            int digit = value % 10;
206            buffer[bufferIndex--] = (char)(digit + '0');
207
208            value = value / 10;
209        } while (value != 0);
210
211        bufferIndex++;
212
213        writeLine(buffer, bufferIndex, 16-bufferIndex);
214    }
215}
216