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