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