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