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 | void write_impl(const char *Ptr, size_t Size) override; |
56 | |
57 | /// current_pos - Return the current position within the stream, |
58 | /// not counting the bytes currently in the buffer. |
59 | uint64_t current_pos() const override { |
60 | // Our current position in the stream is all the contents which have been |
61 | // written to the underlying stream (*not* the current position of the |
62 | // underlying stream). |
63 | return TheStream->tell(); |
64 | } |
65 | |
66 | /// ComputePosition - Examine the given output buffer and figure out the new |
67 | /// position after output. This is safe to call multiple times on the same |
68 | /// buffer, as it records the most recently scanned character and resumes from |
69 | /// there when the buffer has not been flushed. |
70 | void ComputePosition(const char *Ptr, size_t size); |
71 | |
72 | /// UpdatePosition - scan the characters in [Ptr, Ptr+Size), and update the |
73 | /// line and column numbers. Unlike ComputePosition, this must be called |
74 | /// exactly once on each region of the buffer. |
75 | void UpdatePosition(const char *Ptr, size_t Size); |
76 | |
77 | void setStream(raw_ostream &Stream) { |
78 | releaseStream(); |
79 | |
80 | TheStream = &Stream; |
81 | |
82 | // This formatted_raw_ostream inherits from raw_ostream, so it'll do its |
83 | // own buffering, and it doesn't need or want TheStream to do another |
84 | // layer of buffering underneath. Resize the buffer to what TheStream |
85 | // had been using, and tell TheStream not to do its own buffering. |
86 | if (size_t BufferSize = TheStream->GetBufferSize()) |
87 | SetBufferSize(BufferSize); |
88 | else |
89 | SetUnbuffered(); |
90 | TheStream->SetUnbuffered(); |
91 | |
92 | Scanned = nullptr; |
93 | } |
94 | |
95 | public: |
96 | /// formatted_raw_ostream - Open the specified file for |
97 | /// writing. If an error occurs, information about the error is |
98 | /// put into ErrorInfo, and the stream should be immediately |
99 | /// destroyed; the string will be empty if no error occurred. |
100 | /// |
101 | /// As a side effect, the given Stream is set to be Unbuffered. |
102 | /// This is because formatted_raw_ostream does its own buffering, |
103 | /// so it doesn't want another layer of buffering to be happening |
104 | /// underneath it. |
105 | /// |
106 | formatted_raw_ostream(raw_ostream &Stream) |
107 | : TheStream(nullptr), Position(0, 0) { |
108 | setStream(Stream); |
109 | } |
110 | explicit formatted_raw_ostream() : TheStream(nullptr), Position(0, 0) { |
111 | Scanned = nullptr; |
112 | } |
113 | |
114 | ~formatted_raw_ostream() override { |
115 | flush(); |
116 | releaseStream(); |
117 | } |
118 | |
119 | /// PadToColumn - Align the output to some column number. If the current |
120 | /// column is already equal to or more than NewCol, PadToColumn inserts one |
121 | /// space. |
122 | /// |
123 | /// \param NewCol - The column to move to. |
124 | formatted_raw_ostream &PadToColumn(unsigned NewCol); |
125 | |
126 | unsigned getColumn() { |
127 | // Calculate current position, taking buffer contents into account. |
128 | ComputePosition(Ptr: getBufferStart(), size: GetNumBytesInBuffer()); |
129 | return Position.first; |
130 | } |
131 | |
132 | unsigned getLine() { |
133 | // Calculate current position, taking buffer contents into account. |
134 | ComputePosition(Ptr: getBufferStart(), size: GetNumBytesInBuffer()); |
135 | return Position.second; |
136 | } |
137 | |
138 | raw_ostream &resetColor() override { |
139 | TheStream->resetColor(); |
140 | return *this; |
141 | } |
142 | |
143 | raw_ostream &reverseColor() override { |
144 | TheStream->reverseColor(); |
145 | return *this; |
146 | } |
147 | |
148 | raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override { |
149 | TheStream->changeColor(Color, Bold, BG); |
150 | return *this; |
151 | } |
152 | |
153 | bool is_displayed() const override { |
154 | return TheStream->is_displayed(); |
155 | } |
156 | |
157 | private: |
158 | void releaseStream() { |
159 | // Transfer the buffer settings from this raw_ostream back to the underlying |
160 | // stream. |
161 | if (!TheStream) |
162 | return; |
163 | if (size_t BufferSize = GetBufferSize()) |
164 | TheStream->SetBufferSize(BufferSize); |
165 | else |
166 | TheStream->SetUnbuffered(); |
167 | } |
168 | }; |
169 | |
170 | /// fouts() - This returns a reference to a formatted_raw_ostream for |
171 | /// standard output. Use it like: fouts() << "foo" << "bar"; |
172 | formatted_raw_ostream &fouts(); |
173 | |
174 | /// ferrs() - This returns a reference to a formatted_raw_ostream for |
175 | /// standard error. Use it like: ferrs() << "foo" << "bar"; |
176 | formatted_raw_ostream &ferrs(); |
177 | |
178 | /// fdbgs() - This returns a reference to a formatted_raw_ostream for |
179 | /// debug output. Use it like: fdbgs() << "foo" << "bar"; |
180 | formatted_raw_ostream &fdbgs(); |
181 | |
182 | } // end llvm namespace |
183 | |
184 | |
185 | #endif |
186 | |