| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.dx.util; |
| |
| import java.io.FilterWriter; |
| import java.io.IOException; |
| import java.io.Writer; |
| |
| /** |
| * Writer that wraps another writer and passes width-limited and |
| * optionally-prefixed output to its subordinate. When lines are |
| * wrapped they are automatically indented based on the start of the |
| * line. |
| */ |
| public final class IndentingWriter extends FilterWriter { |
| /** {@code null-ok;} optional prefix for every line */ |
| private final String prefix; |
| |
| /** {@code > 0;} the maximum output width */ |
| private final int width; |
| |
| /** {@code > 0;} the maximum indent */ |
| private final int maxIndent; |
| |
| /** {@code >= 0;} current output column (zero-based) */ |
| private int column; |
| |
| /** whether indent spaces are currently being collected */ |
| private boolean collectingIndent; |
| |
| /** {@code >= 0;} current indent amount */ |
| private int indent; |
| |
| /** |
| * Constructs an instance. |
| * |
| * @param out {@code non-null;} writer to send final output to |
| * @param width {@code >= 0;} the maximum output width (not including |
| * {@code prefix}), or {@code 0} for no maximum |
| * @param prefix {@code non-null;} the prefix for each line |
| */ |
| public IndentingWriter(Writer out, int width, String prefix) { |
| super(out); |
| |
| if (out == null) { |
| throw new NullPointerException("out == null"); |
| } |
| |
| if (width < 0) { |
| throw new IllegalArgumentException("width < 0"); |
| } |
| |
| if (prefix == null) { |
| throw new NullPointerException("prefix == null"); |
| } |
| |
| this.width = (width != 0) ? width : Integer.MAX_VALUE; |
| this.maxIndent = width >> 1; |
| this.prefix = (prefix.length() == 0) ? null : prefix; |
| |
| bol(); |
| } |
| |
| /** |
| * Constructs a no-prefix instance. |
| * |
| * @param out {@code non-null;} writer to send final output to |
| * @param width {@code >= 0;} the maximum output width (not including |
| * {@code prefix}), or {@code 0} for no maximum |
| */ |
| public IndentingWriter(Writer out, int width) { |
| this(out, width, ""); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void write(int c) throws IOException { |
| synchronized (lock) { |
| if (collectingIndent) { |
| if (c == ' ') { |
| indent++; |
| if (indent >= maxIndent) { |
| indent = maxIndent; |
| collectingIndent = false; |
| } |
| } else { |
| collectingIndent = false; |
| } |
| } |
| |
| if ((column == width) && (c != '\n')) { |
| out.write('\n'); |
| column = 0; |
| /* |
| * Note: No else, so this should fall through to the next |
| * if statement. |
| */ |
| } |
| |
| if (column == 0) { |
| if (prefix != null) { |
| out.write(prefix); |
| } |
| |
| if (!collectingIndent) { |
| for (int i = 0; i < indent; i++) { |
| out.write(' '); |
| } |
| column = indent; |
| } |
| } |
| |
| out.write(c); |
| |
| if (c == '\n') { |
| bol(); |
| } else { |
| column++; |
| } |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void write(char[] cbuf, int off, int len) throws IOException { |
| synchronized (lock) { |
| while (len > 0) { |
| write(cbuf[off]); |
| off++; |
| len--; |
| } |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void write(String str, int off, int len) throws IOException { |
| synchronized (lock) { |
| while (len > 0) { |
| write(str.charAt(off)); |
| off++; |
| len--; |
| } |
| } |
| } |
| |
| /** |
| * Indicates that output is at the beginning of a line. |
| */ |
| private void bol() { |
| column = 0; |
| collectingIndent = (maxIndent != 0); |
| indent = 0; |
| } |
| } |