1373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver/* 2373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Copyright 2013, Google Inc. 3373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * All rights reserved. 4373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * 5373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Redistribution and use in source and binary forms, with or without 6373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * modification, are permitted provided that the following conditions are 7373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * met: 8373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * 9373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * * Redistributions of source code must retain the above copyright 10373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * notice, this list of conditions and the following disclaimer. 11373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * * Redistributions in binary form must reproduce the above 12373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * copyright notice, this list of conditions and the following disclaimer 13373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * in the documentation and/or other materials provided with the 14373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * distribution. 15373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * * Neither the name of Google Inc. nor the names of its 16373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * contributors may be used to endorse or promote products derived from 17373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * this software without specific prior written permission. 18373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * 19373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver */ 31373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 32373ff22ec69bb6e93646994347b6d80502be1588Ben Gruverpackage org.jf.util; 33373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 34373ff22ec69bb6e93646994347b6d80502be1588Ben Gruverimport java.io.FilterWriter; 35373ff22ec69bb6e93646994347b6d80502be1588Ben Gruverimport java.io.IOException; 36373ff22ec69bb6e93646994347b6d80502be1588Ben Gruverimport java.io.Writer; 37373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 38373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver/** 39373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Writer that wraps another writer and passes width-limited and 40373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * optionally-prefixed output to its subordinate. When lines are 41373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * wrapped they are automatically indented based on the start of the 42373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * line. 43373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver */ 44373ff22ec69bb6e93646994347b6d80502be1588Ben Gruverpublic final class WrappedIndentingWriter extends FilterWriter { 45373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** null-ok; optional prefix for every line */ 46373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private final String prefix; 47373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 48373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** > 0; the maximum output width */ 49373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private final int width; 50373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 51373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** > 0; the maximum indent */ 52373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private final int maxIndent; 53373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 54373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** >= 0; current output column (zero-based) */ 55373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private int column; 56373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 57373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** whether indent spaces are currently being collected */ 58373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private boolean collectingIndent; 59373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 60373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** >= 0; current indent amount */ 61373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private int indent; 62373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 63373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** 64373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Constructs an instance. 65373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * 66373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * @param out non-null; writer to send final output to 67373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * @param width >= 0; the maximum output width (not including 68373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * <code>prefix</code>), or <code>0</code> for no maximum 69373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * @param prefix non-null; the prefix for each line 70373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver */ 71373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver public WrappedIndentingWriter(Writer out, int width, String prefix) { 72373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver super(out); 73373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 74373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (out == null) { 75373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver throw new NullPointerException("out == null"); 76373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 77373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 78373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (width < 0) { 79373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver throw new IllegalArgumentException("width < 0"); 80373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 81373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 82373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (prefix == null) { 83373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver throw new NullPointerException("prefix == null"); 84373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 85373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 86373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver this.width = (width != 0) ? width : Integer.MAX_VALUE; 87373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver this.maxIndent = width >> 1; 88373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver this.prefix = (prefix.length() == 0) ? null : prefix; 89373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 90373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver bol(); 91373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 92373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 93373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** 94373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Constructs a no-prefix instance. 95373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * 96373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * @param out non-null; writer to send final output to 97373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * @param width >= 0; the maximum output width (not including 98373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * <code>prefix</code>), or <code>0</code> for no maximum 99373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver */ 100373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver public WrappedIndentingWriter(Writer out, int width) { 101373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver this(out, width, ""); 102373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 103373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 104373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** {@inheritDoc} */ 105373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver @Override 106373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver public void write(int c) throws IOException { 107373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver synchronized (lock) { 108373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (collectingIndent) { 109373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (c == ' ') { 110373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver indent++; 111373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (indent >= maxIndent) { 112373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver indent = maxIndent; 113373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver collectingIndent = false; 114373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 115373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } else { 116373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver collectingIndent = false; 117373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 118373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 119373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 120373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if ((column == width) && (c != '\n')) { 121373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver out.write('\n'); 122373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver column = 0; 123373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /* 124373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Note: No else, so this should fall through to the next 125373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * if statement. 126373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver */ 127373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 128373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 129373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (column == 0) { 130373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (prefix != null) { 131373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver out.write(prefix); 132373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 133373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 134373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (!collectingIndent) { 135373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver for (int i = 0; i < indent; i++) { 136373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver out.write(' '); 137373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 138373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver column = indent; 139373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 140373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 141373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 142373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver out.write(c); 143373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 144373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver if (c == '\n') { 145373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver bol(); 146373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } else { 147373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver column++; 148373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 149373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 150373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 151373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 152373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** {@inheritDoc} */ 153373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver @Override 154373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver public void write(char[] cbuf, int off, int len) throws IOException { 155373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver synchronized (lock) { 156373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver while (len > 0) { 157373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver write(cbuf[off]); 158373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver off++; 159373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver len--; 160373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 161373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 162373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 163373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 164373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** {@inheritDoc} */ 165373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver @Override 166373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver public void write(String str, int off, int len) throws IOException { 167373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver synchronized (lock) { 168373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver while (len > 0) { 169373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver write(str.charAt(off)); 170373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver off++; 171373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver len--; 172373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 173373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 174373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 175373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver 176373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver /** 177373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver * Indicates that output is at the beginning of a line. 178373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver */ 179373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver private void bol() { 180373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver column = 0; 181373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver collectingIndent = (maxIndent != 0); 182373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver indent = 0; 183373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver } 184373ff22ec69bb6e93646994347b6d80502be1588Ben Gruver} 185