blob: b4f3b8583ed4cf9c416266c26759371116dd66d9 [file] [log] [blame]
Lukacs Berki83e7c712016-10-05 15:56:22 +00001// Copyright 2016 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.runtime;
15
16import java.io.IOException;
17import java.io.OutputStream;
18
19/**
20 * A decorator output stream that does line buffering.
21 */
22public class LineBufferedOutputStream extends OutputStream {
23 private static final int DEFAULT_BUFFER_SIZE = 1024;
24
25 private final OutputStream wrapped;
26 private final byte[] buffer;
27 private int pos;
28
29 public LineBufferedOutputStream(OutputStream wrapped) {
30 this(wrapped, DEFAULT_BUFFER_SIZE);
31 }
32
33 public LineBufferedOutputStream(OutputStream wrapped, int bufferSize) {
34 this.wrapped = wrapped;
35 this.buffer = new byte[bufferSize];
36 this.pos = 0;
37 }
38
Lukacs Berki480a2cf2016-11-21 12:37:46 +000039 private void flushBuffer() throws IOException {
40 int oldPos = pos;
41 // Set pos to zero first so that if the write below throws, we are still in a consistent state.
42 pos = 0;
43 wrapped.write(buffer, 0, oldPos);
44 }
45
Lukacs Berki83e7c712016-10-05 15:56:22 +000046 @Override
47 public synchronized void write(byte[] b, int off, int inlen) throws IOException {
48 if (inlen > buffer.length * 2) {
49 // Do not buffer large writes
50 if (pos > 0) {
Lukacs Berki480a2cf2016-11-21 12:37:46 +000051 flushBuffer();
Lukacs Berki83e7c712016-10-05 15:56:22 +000052 }
53 wrapped.write(b, off, inlen);
54 return;
55 }
56
57 int next = off;
58 while (next < off + inlen) {
59 buffer[pos++] = b[next];
Lukacs Berki480a2cf2016-11-21 12:37:46 +000060 if (b[next] == '\n' || pos == buffer.length) {
61 flushBuffer();
Lukacs Berki83e7c712016-10-05 15:56:22 +000062 }
63
64 next++;
65 }
66 }
67
68 @Override
69 public void write(int byteAsInt) throws IOException {
70 byte b = (byte) byteAsInt; // make sure we work with bytes in comparisons
71 write(new byte[] {b}, 0, 1);
72 }
73
74 @Override
75 public synchronized void flush() throws IOException {
76 if (pos != 0) {
77 wrapped.write(buffer, 0, pos);
78 pos = 0;
79 }
80 wrapped.flush();
81 }
82
83 @Override
84 public synchronized void close() throws IOException {
85 flush();
86 wrapped.close();
87 }
88}