xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/FormattedStream.h (revision 439352ac8257c8419cb4a662abb7f260f31f9932)
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(TheStream->colors_enabled());
97 
98     Scanned = nullptr;
99   }
100 
101   void PreDisableScan() {
102     assert(!DisableScan);
103     ComputePosition(getBufferStart(), 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(getBufferStart(), GetNumBytesInBuffer());
157     return Position.first;
158   }
159 
160   unsigned getLine() {
161     // Calculate current position, taking buffer contents into account.
162     ComputePosition(getBufferStart(), 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