466 lines
14 KiB
C++
466 lines
14 KiB
C++
/* UI_FILE - a generic STDIO like output stream.
|
|
Copyright (C) 1999-2022 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef UI_FILE_H
|
|
#define UI_FILE_H
|
|
|
|
#include <string>
|
|
#include "ui-style.h"
|
|
|
|
/* The abstract ui_file base class. */
|
|
|
|
class ui_file
|
|
{
|
|
public:
|
|
ui_file ();
|
|
virtual ~ui_file () = 0;
|
|
|
|
/* Public non-virtual API. */
|
|
|
|
void printf (const char *, ...) ATTRIBUTE_PRINTF (2, 3);
|
|
|
|
/* Print a NUL-terminated string whose delimiter is QUOTER. Note
|
|
that these routines should only be called for printing things
|
|
which are independent of the language of the program being
|
|
debugged.
|
|
|
|
This will normally escape backslashes and instances of QUOTER.
|
|
If QUOTER is 0, it won't escape backslashes or any quoting
|
|
character. As a side effect, if you pass the backslash character
|
|
as the QUOTER, this will escape backslashes as usual, but not any
|
|
other quoting character. */
|
|
void putstr (const char *str, int quoter);
|
|
|
|
/* Like putstr, but only print the first N characters of STR. If
|
|
ASYNC_SAFE is true, then the output is done via the
|
|
write_async_safe method. */
|
|
void putstrn (const char *str, int n, int quoter, bool async_safe = false);
|
|
|
|
void putc (int c);
|
|
|
|
void vprintf (const char *, va_list) ATTRIBUTE_PRINTF (2, 0);
|
|
|
|
/* Methods below are both public, and overridable by ui_file
|
|
subclasses. */
|
|
|
|
virtual void write (const char *buf, long length_buf) = 0;
|
|
|
|
/* This version of "write" is safe for use in signal handlers. It's
|
|
not guaranteed that all existing output will have been flushed
|
|
first. Implementations are also free to ignore some or all of
|
|
the request. puts_async is not provided as the async versions
|
|
are rarely used, no point in having both for a rarely used
|
|
interface. */
|
|
virtual void write_async_safe (const char *buf, long length_buf)
|
|
{ gdb_assert_not_reached ("write_async_safe"); }
|
|
|
|
/* Some ui_files override this to provide a efficient implementation
|
|
that avoids a strlen. */
|
|
virtual void puts (const char *str)
|
|
{ this->write (str, strlen (str)); }
|
|
|
|
virtual long read (char *buf, long length_buf)
|
|
{ gdb_assert_not_reached ("can't read from this file type"); }
|
|
|
|
virtual bool isatty ()
|
|
{ return false; }
|
|
|
|
/* true indicates terminal output behaviour such as cli_styling.
|
|
This default implementation indicates to do terminal output
|
|
behaviour if the UI_FILE is a tty. A derived class can override
|
|
TERM_OUT to have cli_styling behaviour without being a tty. */
|
|
virtual bool term_out ()
|
|
{ return isatty (); }
|
|
|
|
/* true if ANSI escapes can be used on STREAM. */
|
|
virtual bool can_emit_style_escape ()
|
|
{ return false; }
|
|
|
|
virtual void flush ()
|
|
{}
|
|
|
|
/* If this object has an underlying file descriptor, then return it.
|
|
Otherwise, return -1. */
|
|
virtual int fd () const
|
|
{ return -1; }
|
|
|
|
/* Indicate that if the next sequence of characters overflows the
|
|
line, a newline should be inserted here rather than when it hits
|
|
the end. If INDENT is non-zero, it is a number of spaces to be
|
|
printed to indent the wrapped part on the next line.
|
|
|
|
If the line is already overfull, we immediately print a newline and
|
|
the indentation, and disable further wrapping.
|
|
|
|
If we don't know the width of lines, but we know the page height,
|
|
we must not wrap words, but should still keep track of newlines
|
|
that were explicitly printed.
|
|
|
|
This routine is guaranteed to force out any output which has been
|
|
squirreled away in the wrap_buffer, so wrap_here (0) can be
|
|
used to force out output from the wrap_buffer. */
|
|
virtual void wrap_here (int indent)
|
|
{
|
|
}
|
|
|
|
/* Emit an ANSI style escape for STYLE. */
|
|
virtual void emit_style_escape (const ui_file_style &style);
|
|
|
|
/* Rest the current output style to the empty style. */
|
|
virtual void reset_style ();
|
|
|
|
/* Print STR, bypassing any paging that might be done by this
|
|
ui_file. Note that nearly no code should call this -- it's
|
|
intended for use by gdb_printf, but nothing else. */
|
|
virtual void puts_unfiltered (const char *str)
|
|
{
|
|
this->puts (str);
|
|
}
|
|
|
|
protected:
|
|
|
|
/* The currently applied style. */
|
|
ui_file_style m_applied_style;
|
|
|
|
private:
|
|
|
|
/* Helper function for putstr and putstrn. Print the character C on
|
|
this stream as part of the contents of a literal string whose
|
|
delimiter is QUOTER. */
|
|
void printchar (int c, int quoter, bool async_safe);
|
|
};
|
|
|
|
typedef std::unique_ptr<ui_file> ui_file_up;
|
|
|
|
/* A ui_file that writes to nowhere. */
|
|
|
|
class null_file : public ui_file
|
|
{
|
|
public:
|
|
void write (const char *buf, long length_buf) override;
|
|
void write_async_safe (const char *buf, long sizeof_buf) override;
|
|
void puts (const char *str) override;
|
|
};
|
|
|
|
/* A preallocated null_file stream. */
|
|
extern null_file null_stream;
|
|
|
|
extern int gdb_console_fputs (const char *, FILE *);
|
|
|
|
/* A std::string-based ui_file. Can be used as a scratch buffer for
|
|
collecting output. */
|
|
|
|
class string_file : public ui_file
|
|
{
|
|
public:
|
|
/* Construct a string_file to collect 'raw' output, i.e. without
|
|
'terminal' behaviour such as cli_styling. */
|
|
string_file () : m_term_out (false) {};
|
|
/* If TERM_OUT, construct a string_file with terminal output behaviour
|
|
such as cli_styling)
|
|
else collect 'raw' output like the previous constructor. */
|
|
explicit string_file (bool term_out) : m_term_out (term_out) {};
|
|
~string_file () override;
|
|
|
|
/* Override ui_file methods. */
|
|
|
|
void write (const char *buf, long length_buf) override;
|
|
|
|
long read (char *buf, long length_buf) override
|
|
{ gdb_assert_not_reached ("a string_file is not readable"); }
|
|
|
|
bool term_out () override;
|
|
bool can_emit_style_escape () override;
|
|
|
|
/* string_file-specific public API. */
|
|
|
|
/* Accesses the std::string containing the entire output collected
|
|
so far. */
|
|
const std::string &string () { return m_string; }
|
|
|
|
/* Return an std::string containing the entire output collected so far.
|
|
|
|
The internal buffer is cleared, such that it's ready to build a new
|
|
string. */
|
|
std::string release ()
|
|
{
|
|
std::string ret = std::move (m_string);
|
|
m_string.clear ();
|
|
return ret;
|
|
}
|
|
|
|
/* Set the internal buffer contents to STR. Any existing contents are
|
|
discarded. */
|
|
string_file &operator= (std::string &&str)
|
|
{
|
|
m_string = std::move (str);
|
|
return *this;
|
|
}
|
|
|
|
/* Provide a few convenience methods with the same API as the
|
|
underlying std::string. */
|
|
const char *data () const { return m_string.data (); }
|
|
const char *c_str () const { return m_string.c_str (); }
|
|
size_t size () const { return m_string.size (); }
|
|
bool empty () const { return m_string.empty (); }
|
|
void clear () { return m_string.clear (); }
|
|
|
|
private:
|
|
/* The internal buffer. */
|
|
std::string m_string;
|
|
|
|
bool m_term_out;
|
|
};
|
|
|
|
/* A ui_file implementation that maps directly onto <stdio.h>'s FILE.
|
|
A stdio_file can either own its underlying file, or not. If it
|
|
owns the file, then destroying the stdio_file closes the underlying
|
|
file, otherwise it is left open. */
|
|
|
|
class stdio_file : public ui_file
|
|
{
|
|
public:
|
|
/* Create a ui_file from a previously opened FILE. CLOSE_P
|
|
indicates whether the underlying file should be closed when the
|
|
stdio_file is destroyed. */
|
|
explicit stdio_file (FILE *file, bool close_p = false);
|
|
|
|
/* Create an stdio_file that is not managing any file yet. Call
|
|
open to actually open something. */
|
|
stdio_file ();
|
|
|
|
~stdio_file () override;
|
|
|
|
/* Open NAME in mode MODE, and own the resulting file. Returns true
|
|
on success, false otherwise. If the stdio_file previously owned
|
|
a file, it is closed. */
|
|
bool open (const char *name, const char *mode);
|
|
|
|
void flush () override;
|
|
|
|
void write (const char *buf, long length_buf) override;
|
|
|
|
void write_async_safe (const char *buf, long length_buf) override;
|
|
|
|
void puts (const char *) override;
|
|
|
|
long read (char *buf, long length_buf) override;
|
|
|
|
bool isatty () override;
|
|
|
|
bool can_emit_style_escape () override;
|
|
|
|
/* Return the underlying file descriptor. */
|
|
int fd () const override
|
|
{ return m_fd; }
|
|
|
|
private:
|
|
/* Sets the internal stream to FILE, and saves the FILE's file
|
|
descriptor in M_FD. */
|
|
void set_stream (FILE *file);
|
|
|
|
/* The file. */
|
|
FILE *m_file;
|
|
|
|
/* The associated file descriptor is extracted ahead of time for
|
|
stdio_file::write_async_safe's benefit, in case fileno isn't
|
|
async-safe. */
|
|
int m_fd;
|
|
|
|
/* If true, M_FILE is closed on destruction. */
|
|
bool m_close_p;
|
|
};
|
|
|
|
typedef std::unique_ptr<stdio_file> stdio_file_up;
|
|
|
|
/* Like stdio_file, but specifically for stderr.
|
|
|
|
This exists because there is no real line-buffering on Windows, see
|
|
<http://msdn.microsoft.com/en-us/library/86cebhfs%28v=vs.71%29.aspx>
|
|
so the stdout is either fully-buffered or non-buffered. We can't
|
|
make stdout non-buffered, because of two concerns:
|
|
|
|
1. Non-buffering hurts performance.
|
|
2. Non-buffering may change GDB's behavior when it is interacting
|
|
with a front-end, such as Emacs.
|
|
|
|
We leave stdout as fully buffered, but flush it first when
|
|
something is written to stderr.
|
|
|
|
Note that the 'write_async_safe' method is not overridden, because
|
|
there's no way to flush a stream in an async-safe manner.
|
|
Fortunately, it doesn't really matter, because:
|
|
|
|
1. That method is only used for printing internal debug output
|
|
from signal handlers.
|
|
|
|
2. Windows hosts don't have a concept of async-safeness. Signal
|
|
handlers run in a separate thread, so they can call the regular
|
|
non-async-safe output routines freely.
|
|
*/
|
|
class stderr_file : public stdio_file
|
|
{
|
|
public:
|
|
explicit stderr_file (FILE *stream);
|
|
|
|
/* Override the output routines to flush gdb_stdout before deferring
|
|
to stdio_file for the actual outputting. */
|
|
void write (const char *buf, long length_buf) override;
|
|
void puts (const char *linebuffer) override;
|
|
};
|
|
|
|
/* A ui_file implementation that maps onto two ui-file objects. */
|
|
|
|
class tee_file : public ui_file
|
|
{
|
|
public:
|
|
/* Create a file which writes to both ONE and TWO. ONE will remain
|
|
open when this object is destroyed; but TWO will be closed. */
|
|
tee_file (ui_file *one, ui_file_up &&two);
|
|
~tee_file () override;
|
|
|
|
void write (const char *buf, long length_buf) override;
|
|
void write_async_safe (const char *buf, long length_buf) override;
|
|
void puts (const char *) override;
|
|
|
|
bool isatty () override;
|
|
bool term_out () override;
|
|
bool can_emit_style_escape () override;
|
|
void flush () override;
|
|
|
|
void emit_style_escape (const ui_file_style &style) override
|
|
{
|
|
m_one->emit_style_escape (style);
|
|
m_two->emit_style_escape (style);
|
|
}
|
|
|
|
void reset_style () override
|
|
{
|
|
m_one->reset_style ();
|
|
m_two->reset_style ();
|
|
}
|
|
|
|
void puts_unfiltered (const char *str) override
|
|
{
|
|
m_one->puts_unfiltered (str);
|
|
m_two->puts_unfiltered (str);
|
|
}
|
|
|
|
private:
|
|
/* The two underlying ui_files. */
|
|
ui_file *m_one;
|
|
ui_file_up m_two;
|
|
};
|
|
|
|
/* A ui_file implementation that filters out terminal escape
|
|
sequences. */
|
|
|
|
class no_terminal_escape_file : public stdio_file
|
|
{
|
|
public:
|
|
no_terminal_escape_file ()
|
|
{
|
|
}
|
|
|
|
/* Like the stdio_file methods, but these filter out terminal escape
|
|
sequences. */
|
|
void write (const char *buf, long length_buf) override;
|
|
void puts (const char *linebuffer) override;
|
|
|
|
void emit_style_escape (const ui_file_style &style) override
|
|
{
|
|
}
|
|
|
|
void reset_style () override
|
|
{
|
|
}
|
|
};
|
|
|
|
/* A base class for ui_file types that wrap another ui_file. */
|
|
|
|
class wrapped_file : public ui_file
|
|
{
|
|
public:
|
|
|
|
bool isatty () override
|
|
{ return m_stream->isatty (); }
|
|
|
|
bool term_out () override
|
|
{ return m_stream->term_out (); }
|
|
|
|
bool can_emit_style_escape () override
|
|
{ return m_stream->can_emit_style_escape (); }
|
|
|
|
void flush () override
|
|
{ m_stream->flush (); }
|
|
|
|
void wrap_here (int indent) override
|
|
{ m_stream->wrap_here (indent); }
|
|
|
|
void emit_style_escape (const ui_file_style &style) override
|
|
{ m_stream->emit_style_escape (style); }
|
|
|
|
/* Rest the current output style to the empty style. */
|
|
void reset_style () override
|
|
{ m_stream->reset_style (); }
|
|
|
|
int fd () const override
|
|
{ return m_stream->fd (); }
|
|
|
|
void puts_unfiltered (const char *str) override
|
|
{ m_stream->puts_unfiltered (str); }
|
|
|
|
void write_async_safe (const char *buf, long length_buf) override
|
|
{ return m_stream->write_async_safe (buf, length_buf); }
|
|
|
|
protected:
|
|
|
|
/* Note that this class does not assume ownership of the stream.
|
|
However, a subclass may choose to, by adding a 'delete' to its
|
|
destructor. */
|
|
explicit wrapped_file (ui_file *stream)
|
|
: m_stream (stream)
|
|
{
|
|
}
|
|
|
|
/* The underlying stream. */
|
|
ui_file *m_stream;
|
|
};
|
|
|
|
/* A ui_file that optionally puts a timestamp at the start of each
|
|
line of output. */
|
|
|
|
class timestamped_file : public wrapped_file
|
|
{
|
|
public:
|
|
explicit timestamped_file (ui_file *stream)
|
|
: wrapped_file (stream)
|
|
{
|
|
}
|
|
|
|
DISABLE_COPY_AND_ASSIGN (timestamped_file);
|
|
|
|
void write (const char *buf, long len) override;
|
|
|
|
private:
|
|
|
|
/* True if the next output should be timestamped. */
|
|
bool m_needs_timestamp = true;
|
|
};
|
|
|
|
#endif
|