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