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