| // 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(); | |
| } | |
| } |