| // Copyright 2016 The Bazel Authors. All rights reserved. |
| // |
| // 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.google.devtools.build.lib.runtime; |
| |
| import java.io.IOException; |
| import java.io.OutputStream; |
| |
| /** |
| * A decorator output stream that does line buffering. |
| */ |
| public class LineBufferedOutputStream extends OutputStream { |
| private static final int DEFAULT_BUFFER_SIZE = 1024; |
| |
| private final OutputStream wrapped; |
| private final byte[] buffer; |
| private int pos; |
| |
| public LineBufferedOutputStream(OutputStream wrapped) { |
| this(wrapped, DEFAULT_BUFFER_SIZE); |
| } |
| |
| public LineBufferedOutputStream(OutputStream wrapped, int bufferSize) { |
| this.wrapped = wrapped; |
| this.buffer = new byte[bufferSize]; |
| this.pos = 0; |
| } |
| |
| private void flushBuffer() throws IOException { |
| int oldPos = pos; |
| // Set pos to zero first so that if the write below throws, we are still in a consistent state. |
| pos = 0; |
| wrapped.write(buffer, 0, oldPos); |
| } |
| |
| @Override |
| public synchronized void write(byte[] b, int off, int inlen) throws IOException { |
| if (inlen > buffer.length * 2) { |
| // Do not buffer large writes |
| if (pos > 0) { |
| flushBuffer(); |
| } |
| wrapped.write(b, off, inlen); |
| return; |
| } |
| |
| int next = off; |
| while (next < off + inlen) { |
| buffer[pos++] = b[next]; |
| if (b[next] == '\n' || pos == buffer.length) { |
| flushBuffer(); |
| } |
| |
| next++; |
| } |
| } |
| |
| @Override |
| public void write(int byteAsInt) throws IOException { |
| byte b = (byte) byteAsInt; // make sure we work with bytes in comparisons |
| write(new byte[] {b}, 0, 1); |
| } |
| |
| @Override |
| public synchronized void flush() throws IOException { |
| if (pos != 0) { |
| wrapped.write(buffer, 0, pos); |
| pos = 0; |
| } |
| wrapped.flush(); |
| } |
| |
| @Override |
| public synchronized void close() throws IOException { |
| flush(); |
| wrapped.close(); |
| } |
| } |