blob: b4f3b8583ed4cf9c416266c26759371116dd66d9 [file] [log] [blame]
// 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();
}
}