1 | //===-- llvm/Support/FormattedStream.h - Formatted streams ------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains raw_ostream implementations for streams to do |
10 | // things like pretty-print comments. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_SUPPORT_FORMATTEDSTREAM_H |
15 | #define LLVM_SUPPORT_FORMATTEDSTREAM_H |
16 | |
17 | #include "llvm/ADT/SmallString.h" |
18 | #include "llvm/Support/raw_ostream.h" |
19 | #include <utility> |
20 | |
21 | namespace llvm { |
22 | |
23 | /// formatted_raw_ostream - A raw_ostream that wraps another one and keeps track |
24 | /// of line and column position, allowing padding out to specific column |
25 | /// boundaries and querying the number of lines written to the stream. This |
26 | /// assumes that the contents of the stream is valid UTF-8 encoded text. This |
27 | /// doesn't attempt to handle everything Unicode can do (combining characters, |
28 | /// right-to-left markers, etc), but should cover the cases likely to appear in |
29 | /// source code or diagnostic messages. |
30 | class formatted_raw_ostream : public raw_ostream { |
31 | /// TheStream - The real stream we output to. We set it to be |
32 | /// unbuffered, since we're already doing our own buffering. |
33 | /// |
34 | raw_ostream *TheStream; |
35 | |
36 | /// Position - The current output column and line of the data that's |
37 | /// been flushed and the portion of the buffer that's been |
38 | /// scanned. The line and column scheme is zero-based. |
39 | /// |
40 | std::pair<unsigned, unsigned> Position; |
41 | |
42 | /// Scanned - This points to one past the last character in the |
43 | /// buffer we've scanned. |
44 | /// |
45 | const char *Scanned; |
46 | |
47 | /// PartialUTF8Char - Either empty or a prefix of a UTF-8 code unit sequence |
48 | /// for a Unicode scalar value which should be prepended to the buffer for the |
49 | /// next call to ComputePosition. This is needed when the buffer is flushed |
50 | /// when it ends part-way through the UTF-8 encoding of a Unicode scalar |
51 | /// value, so that we can compute the display width of the character once we |
52 | /// have the rest of it. |
53 | SmallString<4> PartialUTF8Char; |
54 | |
55 | /// DisableScan - Temporarily disable scanning of output. Used to ignore color |
56 | /// codes. |
57 | bool DisableScan; |
58 | |
59 | void write_impl(const char *Ptr, size_t Size) override; |
60 | |
61 | /// current_pos - Return the current position within the stream, |
62 | /// not counting the bytes currently in the buffer. |
63 | uint64_t current_pos() const override { |
64 | // Our current position in the stream is all the contents which have been |
65 | // written to the underlying stream (*not* the current position of the |
66 | // underlying stream). |
67 | return TheStream->tell(); |
68 | } |
69 | |
70 | /// ComputePosition - Examine the given output buffer and figure out the new |
71 | /// position after output. This is safe to call multiple times on the same |
72 | /// buffer, as it records the most recently scanned character and resumes from |
73 | /// there when the buffer has not been flushed. |
74 | void ComputePosition(const char *Ptr, size_t size); |
75 | |
76 | /// UpdatePosition - scan the characters in [Ptr, Ptr+Size), and update the |
77 | /// line and column numbers. Unlike ComputePosition, this must be called |
78 | /// exactly once on each region of the buffer. |
79 | void UpdatePosition(const char *Ptr, size_t Size); |
80 | |
81 | void setStream(raw_ostream &Stream) { |
82 | releaseStream(); |
83 | |
84 | TheStream = &Stream; |
85 | |
86 | // This formatted_raw_ostream inherits from raw_ostream, so it'll do its |
87 | // own buffering, and it doesn't need or want TheStream to do another |
88 | // layer of buffering underneath. Resize the buffer to what TheStream |
89 | // had been using, and tell TheStream not to do its own buffering. |
90 | if (size_t BufferSize = TheStream->GetBufferSize()) |
91 | SetBufferSize(BufferSize); |
92 | else |
93 | SetUnbuffered(); |
94 | TheStream->SetUnbuffered(); |
95 | |
96 | enable_colors(enable: TheStream->colors_enabled()); |
97 | |
98 | Scanned = nullptr; |
99 | } |
100 | |
101 | void PreDisableScan() { |
102 | assert(!DisableScan); |
103 | ComputePosition(Ptr: getBufferStart(), size: GetNumBytesInBuffer()); |
104 | assert(PartialUTF8Char.empty()); |
105 | DisableScan = true; |
106 | } |
107 | |
108 | void PostDisableScan() { |
109 | assert(DisableScan); |
110 | DisableScan = false; |
111 | Scanned = getBufferStart() + GetNumBytesInBuffer(); |
112 | } |
113 | |
114 | struct DisableScanScope { |
115 | formatted_raw_ostream *S; |
116 | |
117 | DisableScanScope(formatted_raw_ostream *FRO) : S(FRO) { |
118 | S->PreDisableScan(); |
119 | } |
120 | ~DisableScanScope() { S->PostDisableScan(); } |
121 | }; |
122 | |
123 | public: |
124 | /// formatted_raw_ostream - Open the specified file for |
125 | /// writing. If an error occurs, information about the error is |
126 | /// put into ErrorInfo, and the stream should be immediately |
127 | /// destroyed; the string will be empty if no error occurred. |
128 | /// |
129 | /// As a side effect, the given Stream is set to be Unbuffered. |
130 | /// This is because formatted_raw_ostream does its own buffering, |
131 | /// so it doesn't want another layer of buffering to be happening |
132 | /// underneath it. |
133 | /// |
134 | formatted_raw_ostream(raw_ostream &Stream) |
135 | : TheStream(nullptr), Position(0, 0), DisableScan(false) { |
136 | setStream(Stream); |
137 | } |
138 | explicit formatted_raw_ostream() |
139 | : TheStream(nullptr), Position(0, 0), Scanned(nullptr), |
140 | DisableScan(false) {} |
141 | |
142 | ~formatted_raw_ostream() override { |
143 | flush(); |
144 | releaseStream(); |
145 | } |
146 | |
147 | /// PadToColumn - Align the output to some column number. If the current |
148 | /// column is already equal to or more than NewCol, PadToColumn inserts one |
149 | /// space. |
150 | /// |
151 | /// \param NewCol - The column to move to. |
152 | formatted_raw_ostream &PadToColumn(unsigned NewCol); |
153 | |
154 | unsigned getColumn() { |
155 | // Calculate current position, taking buffer contents into account. |
156 | ComputePosition(Ptr: getBufferStart(), size: GetNumBytesInBuffer()); |
157 | return Position.first; |
158 | } |
159 | |
160 | unsigned getLine() { |
161 | // Calculate current position, taking buffer contents into account. |
162 | ComputePosition(Ptr: getBufferStart(), size: GetNumBytesInBuffer()); |
163 | return Position.second; |
164 | } |
165 | |
166 | raw_ostream &resetColor() override { |
167 | if (colors_enabled()) { |
168 | DisableScanScope S(this); |
169 | raw_ostream::resetColor(); |
170 | } |
171 | return *this; |
172 | } |
173 | |
174 | raw_ostream &reverseColor() override { |
175 | if (colors_enabled()) { |
176 | DisableScanScope S(this); |
177 | raw_ostream::reverseColor(); |
178 | } |
179 | return *this; |
180 | } |
181 | |
182 | raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override { |
183 | if (colors_enabled()) { |
184 | DisableScanScope S(this); |
185 | raw_ostream::changeColor(Color, Bold, BG); |
186 | } |
187 | return *this; |
188 | } |
189 | |
190 | bool is_displayed() const override { |
191 | return TheStream->is_displayed(); |
192 | } |
193 | |
194 | private: |
195 | void releaseStream() { |
196 | // Transfer the buffer settings from this raw_ostream back to the underlying |
197 | // stream. |
198 | if (!TheStream) |
199 | return; |
200 | if (size_t BufferSize = GetBufferSize()) |
201 | TheStream->SetBufferSize(BufferSize); |
202 | else |
203 | TheStream->SetUnbuffered(); |
204 | } |
205 | }; |
206 | |
207 | /// fouts() - This returns a reference to a formatted_raw_ostream for |
208 | /// standard output. Use it like: fouts() << "foo" << "bar"; |
209 | formatted_raw_ostream &fouts(); |
210 | |
211 | /// ferrs() - This returns a reference to a formatted_raw_ostream for |
212 | /// standard error. Use it like: ferrs() << "foo" << "bar"; |
213 | formatted_raw_ostream &ferrs(); |
214 | |
215 | /// fdbgs() - This returns a reference to a formatted_raw_ostream for |
216 | /// debug output. Use it like: fdbgs() << "foo" << "bar"; |
217 | formatted_raw_ostream &fdbgs(); |
218 | |
219 | } // end llvm namespace |
220 | |
221 | |
222 | #endif |
223 | |