1 package io.jawk.jrt;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.io.ByteArrayOutputStream;
26 import java.io.Flushable;
27 import java.io.IOException;
28 import java.io.OutputStream;
29 import java.io.PrintStream;
30 import java.nio.charset.StandardCharsets;
31 import java.util.Locale;
32 import java.util.Objects;
33 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
34
35
36
37
38
39
40
41
42
43
44 public final class AppendableAwkSink extends AwkSink {
45
46 private final Appendable appendable;
47 private final Object lock = new Object();
48 private final PrintStream printStream;
49
50
51
52
53
54
55 public AppendableAwkSink(Appendable appendableParam) {
56 this(appendableParam, Locale.US);
57 }
58
59
60
61
62
63
64
65 public AppendableAwkSink(Appendable appendableParam, Locale locale) {
66 super(locale);
67 this.appendable = Objects.requireNonNull(appendableParam, "appendable");
68 try {
69 this.printStream = new PrintStream(
70 new AppendableOutputStream(appendable, lock),
71 false,
72 StandardCharsets.UTF_8.name());
73 } catch (java.io.UnsupportedEncodingException e) {
74 throw new IllegalStateException(e);
75 }
76 }
77
78 @Override
79 public void print(String ofs, String ors, String ofmt, Object... values) throws IOException {
80 synchronized (lock) {
81 for (int i = 0; i < values.length; i++) {
82 appendable.append(formatPrintArgument(values[i], ofmt));
83 if (i < values.length - 1) {
84 appendable.append(ofs);
85 }
86 }
87 appendable.append(ors);
88 }
89 }
90
91 @Override
92 public void printf(String ofs, String ors, String ofmt, String format, Object... values)
93 throws IOException {
94 synchronized (lock) {
95 appendable.append(formatPrintfResult(format, values));
96 }
97 }
98
99 @Override
100 public void flush() throws IOException {
101 printStream.flush();
102 if (appendable instanceof Flushable) {
103 synchronized (lock) {
104 ((Flushable) appendable).flush();
105 }
106 }
107 }
108
109 @Override
110 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "Callers need the live PrintStream used for process output pumping.")
111 public PrintStream getPrintStream() {
112 return printStream;
113 }
114
115 private static final class AppendableOutputStream extends OutputStream {
116
117 private final Appendable appendable;
118 private final Object lock;
119 private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
120
121 private AppendableOutputStream(Appendable appendableParam, Object lockParam) {
122 this.appendable = appendableParam;
123 this.lock = lockParam;
124 }
125
126 @Override
127 public void write(int value) {
128 synchronized (lock) {
129 buffer.write(value);
130 }
131 }
132
133 @Override
134 public void write(byte[] bytes, int off, int len) {
135 synchronized (lock) {
136 buffer.write(bytes, off, len);
137 }
138 }
139
140 @Override
141 public void flush() throws IOException {
142 synchronized (lock) {
143 if (buffer.size() > 0) {
144 appendable.append(buffer.toString(StandardCharsets.UTF_8.name()));
145 buffer.reset();
146 }
147 }
148 }
149
150 @Override
151 public void close() throws IOException {
152 flush();
153 }
154 }
155 }