|  | /* Output generating routines for GDB. | 
|  |  | 
|  | Copyright (C) 1999-2024 Free Software Foundation, Inc. | 
|  |  | 
|  | Contributed by Cygnus Solutions. | 
|  | Written by Fernando Nasser for Cygnus. | 
|  |  | 
|  | 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 GDB_UI_OUT_H | 
|  | #define GDB_UI_OUT_H | 
|  |  | 
|  | #include <vector> | 
|  |  | 
|  | #include "gdbsupport/enum-flags.h" | 
|  | #include "ui-style.h" | 
|  |  | 
|  | class ui_out_level; | 
|  | class ui_out_table; | 
|  | struct ui_file; | 
|  |  | 
|  | /* the current ui_out */ | 
|  |  | 
|  | /* FIXME: This should not be a global but something passed down from main.c | 
|  | or top.c.  */ | 
|  | extern struct ui_out **current_ui_current_uiout_ptr (void); | 
|  | #define current_uiout (*current_ui_current_uiout_ptr ()) | 
|  |  | 
|  | /* alignment enum */ | 
|  | enum ui_align | 
|  | { | 
|  | ui_left = -1, | 
|  | ui_center, | 
|  | ui_right, | 
|  | ui_noalign | 
|  | }; | 
|  |  | 
|  | /* flags enum */ | 
|  | enum ui_out_flag | 
|  | { | 
|  | ui_source_list = (1 << 0), | 
|  | fix_multi_location_breakpoint_output = (1 << 1), | 
|  | /* This indicates that %pF should be disallowed in a printf format | 
|  | string.  */ | 
|  | disallow_ui_out_field = (1 << 2), | 
|  | fix_breakpoint_script_output = (1 << 3), | 
|  | }; | 
|  |  | 
|  | DEF_ENUM_FLAGS_TYPE (ui_out_flag, ui_out_flags); | 
|  |  | 
|  | /* Prototypes for ui-out API.  */ | 
|  |  | 
|  | /* A result is a recursive data structure consisting of lists and | 
|  | tuples.  */ | 
|  |  | 
|  | enum ui_out_type | 
|  | { | 
|  | ui_out_type_tuple, | 
|  | ui_out_type_list | 
|  | }; | 
|  |  | 
|  | /* The possible kinds of fields.  */ | 
|  | enum class field_kind | 
|  | { | 
|  | /* "FIELD_STRING" needs a funny name to avoid clashes with tokens | 
|  | named "STRING".  See PR build/25250.  FIELD_SIGNED is given a | 
|  | similar name for consistency.  */ | 
|  | FIELD_SIGNED, | 
|  | FIELD_STRING, | 
|  | }; | 
|  |  | 
|  | /* The base type of all fields that can be emitted using %pF.  */ | 
|  |  | 
|  | struct base_field_s | 
|  | { | 
|  | const char *name; | 
|  | field_kind kind; | 
|  | }; | 
|  |  | 
|  | /* A signed integer field, to be passed to %pF in format strings.  */ | 
|  |  | 
|  | struct signed_field_s : base_field_s | 
|  | { | 
|  | LONGEST val; | 
|  | }; | 
|  |  | 
|  | /* Construct a temporary signed_field_s on the caller's stack and | 
|  | return a pointer to the constructed object.  We use this because | 
|  | it's not possible to pass a reference via va_args.  */ | 
|  |  | 
|  | static inline signed_field_s * | 
|  | signed_field (const char *name, LONGEST val, | 
|  | signed_field_s &&tmp = {}) | 
|  | { | 
|  | tmp.name = name; | 
|  | tmp.kind = field_kind::FIELD_SIGNED; | 
|  | tmp.val = val; | 
|  | return &tmp; | 
|  | } | 
|  |  | 
|  | /* A string field, to be passed to %pF in format strings.  */ | 
|  |  | 
|  | struct string_field_s : base_field_s | 
|  | { | 
|  | const char *str; | 
|  | }; | 
|  |  | 
|  | /* Construct a temporary string_field_s on the caller's stack and | 
|  | return a pointer to the constructed object.  We use this because | 
|  | it's not possible to pass a reference via va_args.  */ | 
|  |  | 
|  | static inline string_field_s * | 
|  | string_field (const char *name, const char *str, | 
|  | string_field_s &&tmp = {}) | 
|  | { | 
|  | tmp.name = name; | 
|  | tmp.kind = field_kind::FIELD_STRING; | 
|  | tmp.str = str; | 
|  | return &tmp; | 
|  | } | 
|  |  | 
|  | /* A styled string.  */ | 
|  |  | 
|  | struct styled_string_s | 
|  | { | 
|  | /* The style.  */ | 
|  | ui_file_style style; | 
|  |  | 
|  | /* The string.  */ | 
|  | const char *str; | 
|  | }; | 
|  |  | 
|  | /* Construct a temporary styled_string_s on the caller's stack and | 
|  | return a pointer to the constructed object.  We use this because | 
|  | it's not possible to pass a reference via va_args.  */ | 
|  |  | 
|  | static inline styled_string_s * | 
|  | styled_string (const ui_file_style &style, const char *str, | 
|  | styled_string_s &&tmp = {}) | 
|  | { | 
|  | tmp.style = style; | 
|  | tmp.str = str; | 
|  | return &tmp; | 
|  | } | 
|  |  | 
|  | class ui_out | 
|  | { | 
|  | public: | 
|  |  | 
|  | explicit ui_out (ui_out_flags flags = 0); | 
|  | virtual ~ui_out (); | 
|  |  | 
|  | DISABLE_COPY_AND_ASSIGN (ui_out); | 
|  |  | 
|  | void push_level (ui_out_type type); | 
|  | void pop_level (ui_out_type type); | 
|  |  | 
|  | /* A table can be considered a special tuple/list combination with the | 
|  | implied structure: ``table = { hdr = { header, ... } , body = [ { | 
|  | field, ... }, ... ] }''.  If NR_ROWS is negative then there is at | 
|  | least one row.  */ | 
|  |  | 
|  | void table_begin (int nr_cols, int nr_rows, const std::string &tblid); | 
|  | void table_header (int width, ui_align align, const std::string &col_name, | 
|  | const std::string &col_hdr); | 
|  | void table_body (); | 
|  | void table_end (); | 
|  |  | 
|  | void begin (ui_out_type type, const char *id); | 
|  | void end (ui_out_type type); | 
|  |  | 
|  | void field_signed (const char *fldname, LONGEST value, | 
|  | const ui_file_style &style = ui_file_style ()); | 
|  | void field_fmt_signed (int width, ui_align align, const char *fldname, | 
|  | LONGEST value); | 
|  | /* Like field_signed, but print an unsigned value.  */ | 
|  | void field_unsigned (const char *fldname, ULONGEST value); | 
|  | void field_core_addr (const char *fldname, struct gdbarch *gdbarch, | 
|  | CORE_ADDR address); | 
|  | void field_string (const char *fldname, const char *string, | 
|  | const ui_file_style &style = ui_file_style ()); | 
|  | void field_string (const char *fldname, const std::string &string, | 
|  | const ui_file_style &style = ui_file_style ()) | 
|  | { | 
|  | field_string (fldname, string.c_str (), style); | 
|  | } | 
|  | void field_stream (const char *fldname, string_file &stream, | 
|  | const ui_file_style &style = ui_file_style ()); | 
|  | void field_skip (const char *fldname); | 
|  | void field_fmt (const char *fldname, const char *format, ...) | 
|  | ATTRIBUTE_PRINTF (3, 4); | 
|  | void field_fmt (const char *fldname, const ui_file_style &style, | 
|  | const char *format, ...) | 
|  | ATTRIBUTE_PRINTF (4, 5); | 
|  |  | 
|  | void spaces (int numspaces) { do_spaces (numspaces); } | 
|  | void text (const char *string) { do_text (string); } | 
|  | void text (const std::string &string) { text (string.c_str ()); } | 
|  |  | 
|  | /* Output a printf-style formatted string.  In addition to the usual | 
|  | printf format specs, this supports a few GDB-specific | 
|  | formatters: | 
|  |  | 
|  | - '%pF' - output a field. | 
|  |  | 
|  | The argument is a field, wrapped in any of the base_field_s | 
|  | subclasses.  signed_field for integer fields, string_field for | 
|  | string fields.  This is preferred over separate | 
|  | uiout->field_signed(), uiout_>field_string() etc. calls when | 
|  | the formatted message is translatable.  E.g.: | 
|  |  | 
|  | uiout->message (_("\nWatchpoint %pF deleted because the program has " | 
|  | "left the block in\n" | 
|  | "which its expression is valid.\n"), | 
|  | signed_field ("wpnum", b->number)); | 
|  |  | 
|  | - '%p[' - output the following text in a specified style. | 
|  | '%p]' - output the following text in the default style. | 
|  |  | 
|  | The argument to '%p[' is a ui_file_style pointer.  The argument | 
|  | to '%p]' must be nullptr. | 
|  |  | 
|  | This is useful when you want to output some portion of a string | 
|  | literal in some style.  E.g.: | 
|  |  | 
|  | uiout->message (_(" %p[<repeats %u times>%p]"), | 
|  | metadata_style.style ().ptr (), | 
|  | reps, repeats, nullptr); | 
|  |  | 
|  | - '%ps' - output a styled string. | 
|  |  | 
|  | The argument is the result of a call to styled_string.  This is | 
|  | useful when you want to output some runtime-generated string in | 
|  | some style.  E.g.: | 
|  |  | 
|  | uiout->message (_("this is a target address %ps.\n"), | 
|  | styled_string (address_style.style (), | 
|  | paddress (gdbarch, pc))); | 
|  |  | 
|  | Note that these all "abuse" the %p printf format spec, in order | 
|  | to be compatible with GCC's printf format checking.  This is OK | 
|  | because code in GDB that wants to print a host address should use | 
|  | host_address_to_string instead of %p.  */ | 
|  | void message (const char *format, ...) ATTRIBUTE_PRINTF (2, 3); | 
|  | void vmessage (const ui_file_style &in_style, | 
|  | const char *format, va_list args) ATTRIBUTE_PRINTF (3, 0); | 
|  |  | 
|  | void wrap_hint (int indent) { do_wrap_hint (indent); } | 
|  |  | 
|  | void flush () { do_flush (); } | 
|  |  | 
|  | /* Redirect the output of a ui_out object temporarily.  */ | 
|  | void redirect (ui_file *outstream) { do_redirect (outstream); } | 
|  |  | 
|  | ui_out_flags test_flags (ui_out_flags mask) | 
|  | { return m_flags & mask; } | 
|  |  | 
|  | /* HACK: Code in GDB is currently checking to see the type of ui_out | 
|  | builder when determining which output to produce.  This function is | 
|  | a hack to encapsulate that test.  Once GDB manages to separate the | 
|  | CLI/MI from the core of GDB the problem should just go away ....  */ | 
|  |  | 
|  | bool is_mi_like_p () const { return do_is_mi_like_p (); } | 
|  |  | 
|  | bool query_table_field (int colno, int *width, int *alignment, | 
|  | const char **col_name); | 
|  |  | 
|  | /* Return true if this stream is prepared to handle style | 
|  | escapes.  */ | 
|  | virtual bool can_emit_style_escape () const = 0; | 
|  |  | 
|  | /* Return the ui_file currently used for output.  */ | 
|  | virtual ui_file *current_stream () const = 0; | 
|  |  | 
|  | /* An object that starts and finishes displaying progress updates.  */ | 
|  | class progress_update | 
|  | { | 
|  | public: | 
|  | /* Represents the printing state of a progress update.  */ | 
|  | enum state | 
|  | { | 
|  | /* Printing will start with the next update.  */ | 
|  | START, | 
|  | /* Printing has already started.  */ | 
|  | WORKING, | 
|  | /* Progress bar printing has already started.  */ | 
|  | BAR | 
|  | }; | 
|  |  | 
|  | /* SHOULD_PRINT indicates whether something should be printed for a tty.  */ | 
|  | progress_update () | 
|  | { | 
|  | m_uiout = current_uiout; | 
|  | m_uiout->do_progress_start (); | 
|  | } | 
|  |  | 
|  | ~progress_update () | 
|  | { | 
|  | m_uiout->do_progress_end (); | 
|  | } | 
|  |  | 
|  | progress_update (const progress_update &) = delete; | 
|  | progress_update &operator= (const progress_update &) = delete; | 
|  |  | 
|  | /* Emit some progress for this progress meter.  Includes current | 
|  | amount of progress made and total amount in the display.  */ | 
|  | void update_progress (const std::string& msg, const char *unit, | 
|  | double cur, double total) | 
|  | { | 
|  | m_uiout->do_progress_notify (msg, unit, cur, total); | 
|  | } | 
|  |  | 
|  | /* Emit some progress for this progress meter.  */ | 
|  | void update_progress (const std::string& msg) | 
|  | { | 
|  | m_uiout->do_progress_notify (msg, "", -1, -1); | 
|  | } | 
|  |  | 
|  | private: | 
|  |  | 
|  | struct ui_out *m_uiout; | 
|  | }; | 
|  |  | 
|  | protected: | 
|  |  | 
|  | virtual void do_table_begin (int nbrofcols, int nr_rows, const char *tblid) | 
|  | = 0; | 
|  | virtual void do_table_body () = 0; | 
|  | virtual void do_table_end () = 0; | 
|  | virtual void do_table_header (int width, ui_align align, | 
|  | const std::string &col_name, | 
|  | const std::string &col_hdr) = 0; | 
|  |  | 
|  | virtual void do_begin (ui_out_type type, const char *id) = 0; | 
|  | virtual void do_end (ui_out_type type) = 0; | 
|  | virtual void do_field_signed (int fldno, int width, ui_align align, | 
|  | const char *fldname, LONGEST value, | 
|  | const ui_file_style &style) = 0; | 
|  | virtual void do_field_unsigned (int fldno, int width, ui_align align, | 
|  | const char *fldname, ULONGEST value) = 0; | 
|  | virtual void do_field_skip (int fldno, int width, ui_align align, | 
|  | const char *fldname) = 0; | 
|  | virtual void do_field_string (int fldno, int width, ui_align align, | 
|  | const char *fldname, const char *string, | 
|  | const ui_file_style &style) = 0; | 
|  | virtual void do_field_fmt (int fldno, int width, ui_align align, | 
|  | const char *fldname, const ui_file_style &style, | 
|  | const char *format, va_list args) | 
|  | ATTRIBUTE_PRINTF (7, 0) = 0; | 
|  | virtual void do_spaces (int numspaces) = 0; | 
|  | virtual void do_text (const char *string) = 0; | 
|  | virtual void do_message (const ui_file_style &style, | 
|  | const char *format, va_list args) | 
|  | ATTRIBUTE_PRINTF (3,0) = 0; | 
|  | virtual void do_wrap_hint (int indent) = 0; | 
|  | virtual void do_flush () = 0; | 
|  | virtual void do_redirect (struct ui_file *outstream) = 0; | 
|  |  | 
|  | virtual void do_progress_start () = 0; | 
|  | virtual void do_progress_notify (const std::string &, const char *, | 
|  | double, double) = 0; | 
|  | virtual void do_progress_end () = 0; | 
|  |  | 
|  | /* Set as not MI-like by default.  It is overridden in subclasses if | 
|  | necessary.  */ | 
|  |  | 
|  | virtual bool do_is_mi_like_p () const | 
|  | { return false; } | 
|  |  | 
|  | private: | 
|  | void call_do_message (const ui_file_style &style, const char *format, | 
|  | ...); | 
|  |  | 
|  | ui_out_flags m_flags; | 
|  |  | 
|  | /* Vector to store and track the ui-out levels.  */ | 
|  | std::vector<std::unique_ptr<ui_out_level>> m_levels; | 
|  |  | 
|  | /* A table, if any.  At present only a single table is supported.  */ | 
|  | std::unique_ptr<ui_out_table> m_table_up; | 
|  |  | 
|  | void verify_field (int *fldno, int *width, ui_align *align); | 
|  |  | 
|  | int level () const; | 
|  | ui_out_level *current_level () const; | 
|  | }; | 
|  |  | 
|  | /* Start a new tuple or list on construction, and end it on | 
|  | destruction.  Normally this is used via the typedefs | 
|  | ui_out_emit_tuple and ui_out_emit_list.  */ | 
|  | template<ui_out_type Type> | 
|  | class ui_out_emit_type | 
|  | { | 
|  | public: | 
|  |  | 
|  | ui_out_emit_type (struct ui_out *uiout, const char *id) | 
|  | : m_uiout (uiout) | 
|  | { | 
|  | uiout->begin (Type, id); | 
|  | } | 
|  |  | 
|  | ~ui_out_emit_type () | 
|  | { | 
|  | m_uiout->end (Type); | 
|  | } | 
|  |  | 
|  | DISABLE_COPY_AND_ASSIGN (ui_out_emit_type); | 
|  |  | 
|  | private: | 
|  |  | 
|  | struct ui_out *m_uiout; | 
|  | }; | 
|  |  | 
|  | typedef ui_out_emit_type<ui_out_type_tuple> ui_out_emit_tuple; | 
|  | typedef ui_out_emit_type<ui_out_type_list> ui_out_emit_list; | 
|  |  | 
|  | /* Start a new table on construction, and end the table on | 
|  | destruction.  */ | 
|  | class ui_out_emit_table | 
|  | { | 
|  | public: | 
|  |  | 
|  | ui_out_emit_table (struct ui_out *uiout, int nr_cols, int nr_rows, | 
|  | const char *tblid) | 
|  | : m_uiout (uiout) | 
|  | { | 
|  | m_uiout->table_begin (nr_cols, nr_rows, tblid); | 
|  | } | 
|  |  | 
|  | ~ui_out_emit_table () | 
|  | { | 
|  | m_uiout->table_end (); | 
|  | } | 
|  |  | 
|  | ui_out_emit_table (const ui_out_emit_table &) = delete; | 
|  | ui_out_emit_table &operator= (const ui_out_emit_table &) = delete; | 
|  |  | 
|  | private: | 
|  |  | 
|  | struct ui_out *m_uiout; | 
|  | }; | 
|  |  | 
|  | /* On construction, redirect a uiout to a given stream.  On | 
|  | destruction, pop the last redirection by calling the uiout's | 
|  | redirect method with a NULL parameter.  */ | 
|  | class ui_out_redirect_pop | 
|  | { | 
|  | public: | 
|  |  | 
|  | ui_out_redirect_pop (ui_out *uiout, ui_file *stream) | 
|  | : m_uiout (uiout) | 
|  | { | 
|  | m_uiout->redirect (stream); | 
|  | } | 
|  |  | 
|  | ~ui_out_redirect_pop () | 
|  | { | 
|  | m_uiout->redirect (NULL); | 
|  | } | 
|  |  | 
|  | ui_out_redirect_pop (const ui_out_redirect_pop &) = delete; | 
|  | ui_out_redirect_pop &operator= (const ui_out_redirect_pop &) = delete; | 
|  |  | 
|  | private: | 
|  | struct ui_out *m_uiout; | 
|  | }; | 
|  |  | 
|  | struct buffered_streams; | 
|  |  | 
|  | /* Organizes writes to a collection of buffered output streams | 
|  | so that when flushed, output is written to all streams in | 
|  | chronological order.  */ | 
|  |  | 
|  | struct buffer_group | 
|  | { | 
|  | buffer_group (ui_out *uiout); | 
|  |  | 
|  | /* Flush all buffered writes to the underlying output streams.  */ | 
|  | void flush () const; | 
|  |  | 
|  | /* Record contents of BUF and associate it with STREAM.  */ | 
|  | void write (const char *buf, long length_buf, ui_file *stream); | 
|  |  | 
|  | /* Record a wrap_here and associate it with STREAM.  */ | 
|  | void wrap_here (int indent, ui_file *stream); | 
|  |  | 
|  | /* Record a call to flush and associate it with STREAM.  */ | 
|  | void flush_here (ui_file *stream); | 
|  |  | 
|  | private: | 
|  |  | 
|  | struct output_unit | 
|  | { | 
|  | output_unit (std::string msg, int wrap_hint = -1, bool flush = false) | 
|  | : m_msg (msg), m_wrap_hint (wrap_hint), m_flush (flush) | 
|  | {} | 
|  |  | 
|  | /* Write contents of this output_unit to the underlying stream.  */ | 
|  | void flush () const; | 
|  |  | 
|  | /* Underlying stream for which this output unit will be written to.  */ | 
|  | ui_file *m_stream; | 
|  |  | 
|  | /* String to be written to underlying buffer.  */ | 
|  | std::string m_msg; | 
|  |  | 
|  | /* Argument to wrap_here.  -1 indicates no wrap.  Used to call wrap_here | 
|  | during buffer flush.  */ | 
|  | int m_wrap_hint; | 
|  |  | 
|  | /* Indicate that the underlying output stream's flush should be called.  */ | 
|  | bool m_flush; | 
|  | }; | 
|  |  | 
|  | /* Output_units to be written to buffered output streams.  */ | 
|  | std::vector<output_unit> m_buffered_output; | 
|  |  | 
|  | /* Buffered output streams.  */ | 
|  | std::unique_ptr<buffered_streams> m_buffered_streams; | 
|  | }; | 
|  |  | 
|  | /* If FILE is a buffering_file, return it's underlying stream.  */ | 
|  |  | 
|  | extern ui_file *get_unbuffered (ui_file *file); | 
|  |  | 
|  | /* Buffer output to gdb_stdout and gdb_stderr for the duration of FUNC.  */ | 
|  |  | 
|  | template<typename F, typename... Arg> | 
|  | void | 
|  | do_with_buffered_output (F func, ui_out *uiout, Arg... args) | 
|  | { | 
|  | buffer_group g (uiout); | 
|  |  | 
|  | try | 
|  | { | 
|  | func (uiout, std::forward<Arg> (args)...); | 
|  | } | 
|  | catch (gdb_exception &ex) | 
|  | { | 
|  | /* Ideally flush would be called in the destructor of buffer_group, | 
|  | however flushing might cause an exception to be thrown.  Catch it | 
|  | and ensure the first exception propagates.  */ | 
|  | try | 
|  | { | 
|  | g.flush (); | 
|  | } | 
|  | catch (const gdb_exception &) | 
|  | { | 
|  | } | 
|  |  | 
|  | throw_exception (std::move (ex)); | 
|  | } | 
|  |  | 
|  | /* Try was successful.  Let any further exceptions propagate.  */ | 
|  | g.flush (); | 
|  | } | 
|  |  | 
|  | /* Accumulate writes to an underlying ui_file.  Output to the | 
|  | underlying file is deferred until required.  */ | 
|  |  | 
|  | struct buffering_file : public ui_file | 
|  | { | 
|  | buffering_file (buffer_group *group, ui_file *stream) | 
|  | : m_group (group), | 
|  | m_stream (stream) | 
|  | { /* Nothing.  */ } | 
|  |  | 
|  | /* Return the underlying output stream.  */ | 
|  | ui_file *stream () const | 
|  | { | 
|  | return m_stream; | 
|  | } | 
|  |  | 
|  | /* Record the contents of BUF.  */ | 
|  | void write (const char *buf, long length_buf) override | 
|  | { | 
|  | m_group->write (buf, length_buf, m_stream); | 
|  | } | 
|  |  | 
|  | /* Record a wrap_here call with argument INDENT.  */ | 
|  | void wrap_here (int indent) override | 
|  | { | 
|  | m_group->wrap_here (indent, m_stream); | 
|  | } | 
|  |  | 
|  | /* Return true if the underlying stream is a tty.  */ | 
|  | bool isatty () override | 
|  | { | 
|  | return m_stream->isatty (); | 
|  | } | 
|  |  | 
|  | /* Return true if ANSI escapes can be used on the underlying stream.  */ | 
|  | bool can_emit_style_escape () override | 
|  | { | 
|  | return m_stream->can_emit_style_escape (); | 
|  | } | 
|  |  | 
|  | /* Flush the underlying output stream.  */ | 
|  | void flush () override | 
|  | { | 
|  | return m_group->flush_here (m_stream); | 
|  | } | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* Coordinates buffering across multiple buffering_files.  */ | 
|  | buffer_group *m_group; | 
|  |  | 
|  | /* The underlying output stream.  */ | 
|  | ui_file *m_stream; | 
|  | }; | 
|  |  | 
|  | /* Attaches and detaches buffers for each of the gdb_std* streams.  */ | 
|  |  | 
|  | struct buffered_streams | 
|  | { | 
|  | buffered_streams (buffer_group *group, ui_out *uiout); | 
|  |  | 
|  | ~buffered_streams () | 
|  | { | 
|  | this->remove_buffers (); | 
|  | } | 
|  |  | 
|  | /* Remove buffering_files from all underlying streams.  */ | 
|  | void remove_buffers (); | 
|  |  | 
|  | private: | 
|  |  | 
|  | /* True if buffers are still attached to each underlying output stream.  */ | 
|  | bool m_buffers_in_place; | 
|  |  | 
|  | /* Buffers for each gdb_std* output stream.  */ | 
|  | buffering_file m_buffered_stdout; | 
|  | buffering_file m_buffered_stderr; | 
|  | buffering_file m_buffered_stdlog; | 
|  | buffering_file m_buffered_stdtarg; | 
|  |  | 
|  | /* Buffer for current_uiout's output stream.  */ | 
|  | std::optional<buffering_file> m_buffered_current_uiout; | 
|  |  | 
|  | /* Additional ui_out being buffered.  */ | 
|  | ui_out *m_uiout; | 
|  |  | 
|  | /* Buffer for m_uiout's output stream.  */ | 
|  | std::optional<buffering_file> m_buffered_uiout; | 
|  | }; | 
|  |  | 
|  | #endif /* GDB_UI_OUT_H */ |