1 /* 2 * Copyright 2013, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 package org.jf.util; 33 34 import java.io.FilterWriter; 35 import java.io.IOException; 36 import java.io.Writer; 37 38 /** 39 * Writer that wraps another writer and passes width-limited and 40 * optionally-prefixed output to its subordinate. When lines are 41 * wrapped they are automatically indented based on the start of the 42 * line. 43 */ 44 public final class OldWrappedIndentingWriter extends FilterWriter { 45 /** null-ok; optional prefix for every line */ 46 private final String prefix; 47 48 /** > 0; the maximum output width */ 49 private final int width; 50 51 /** > 0; the maximum indent */ 52 private final int maxIndent; 53 54 /** >= 0; current output column (zero-based) */ 55 private int column; 56 57 /** whether indent spaces are currently being collected */ 58 private boolean collectingIndent; 59 60 /** >= 0; current indent amount */ 61 private int indent; 62 63 /** 64 * Constructs an instance. 65 * 66 * @param out non-null; writer to send final output to 67 * @param width >= 0; the maximum output width (not including 68 * <code>prefix</code>), or <code>0</code> for no maximum 69 * @param prefix non-null; the prefix for each line 70 */ OldWrappedIndentingWriter(Writer out, int width, String prefix)71 public OldWrappedIndentingWriter(Writer out, int width, String prefix) { 72 super(out); 73 74 if (out == null) { 75 throw new NullPointerException("out == null"); 76 } 77 78 if (width < 0) { 79 throw new IllegalArgumentException("width < 0"); 80 } 81 82 if (prefix == null) { 83 throw new NullPointerException("prefix == null"); 84 } 85 86 this.width = (width != 0) ? width : Integer.MAX_VALUE; 87 this.maxIndent = width >> 1; 88 this.prefix = (prefix.length() == 0) ? null : prefix; 89 90 bol(); 91 } 92 93 /** 94 * Constructs a no-prefix instance. 95 * 96 * @param out non-null; writer to send final output to 97 * @param width >= 0; the maximum output width (not including 98 * <code>prefix</code>), or <code>0</code> for no maximum 99 */ OldWrappedIndentingWriter(Writer out, int width)100 public OldWrappedIndentingWriter(Writer out, int width) { 101 this(out, width, ""); 102 } 103 104 /** {@inheritDoc} */ 105 @Override write(int c)106 public void write(int c) throws IOException { 107 synchronized (lock) { 108 if (collectingIndent) { 109 if (c == ' ') { 110 indent++; 111 if (indent >= maxIndent) { 112 indent = maxIndent; 113 collectingIndent = false; 114 } 115 } else { 116 collectingIndent = false; 117 } 118 } 119 120 if ((column == width) && (c != '\n')) { 121 out.write('\n'); 122 column = 0; 123 /* 124 * Note: No else, so this should fall through to the next 125 * if statement. 126 */ 127 } 128 129 if (column == 0) { 130 if (prefix != null) { 131 out.write(prefix); 132 } 133 134 if (!collectingIndent) { 135 for (int i = 0; i < indent; i++) { 136 out.write(' '); 137 } 138 column = indent; 139 } 140 } 141 142 out.write(c); 143 144 if (c == '\n') { 145 bol(); 146 } else { 147 column++; 148 } 149 } 150 } 151 152 /** {@inheritDoc} */ 153 @Override write(char[] cbuf, int off, int len)154 public void write(char[] cbuf, int off, int len) throws IOException { 155 synchronized (lock) { 156 while (len > 0) { 157 write(cbuf[off]); 158 off++; 159 len--; 160 } 161 } 162 } 163 164 /** {@inheritDoc} */ 165 @Override write(String str, int off, int len)166 public void write(String str, int off, int len) throws IOException { 167 synchronized (lock) { 168 while (len > 0) { 169 write(str.charAt(off)); 170 off++; 171 len--; 172 } 173 } 174 } 175 176 /** 177 * Indicates that output is at the beginning of a line. 178 */ bol()179 private void bol() { 180 column = 0; 181 collectingIndent = (maxIndent != 0); 182 indent = 0; 183 } 184 } 185