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.
current_pos()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 
setStream(raw_ostream & Stream)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   ///
formatted_raw_ostream(raw_ostream & Stream)106   formatted_raw_ostream(raw_ostream &Stream)
107       : TheStream(nullptr), Position(0, 0) {
108     setStream(Stream);
109   }
formatted_raw_ostream()110   explicit formatted_raw_ostream() : TheStream(nullptr), Position(0, 0) {
111     Scanned = nullptr;
112   }
113 
~formatted_raw_ostream()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 
getColumn()126   unsigned getColumn() {
127     // Calculate current position, taking buffer contents into account.
128     ComputePosition(getBufferStart(), GetNumBytesInBuffer());
129     return Position.first;
130   }
131 
getLine()132   unsigned getLine() {
133     // Calculate current position, taking buffer contents into account.
134     ComputePosition(getBufferStart(), GetNumBytesInBuffer());
135     return Position.second;
136   }
137 
resetColor()138   raw_ostream &resetColor() override {
139     TheStream->resetColor();
140     return *this;
141   }
142 
reverseColor()143   raw_ostream &reverseColor() override {
144     TheStream->reverseColor();
145     return *this;
146   }
147 
changeColor(enum Colors Color,bool Bold,bool BG)148   raw_ostream &changeColor(enum Colors Color, bool Bold, bool BG) override {
149     TheStream->changeColor(Color, Bold, BG);
150     return *this;
151   }
152 
is_displayed()153   bool is_displayed() const override {
154     return TheStream->is_displayed();
155   }
156 
157 private:
releaseStream()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