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