]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Move buffered stream to new files
authorTom Tromey <tom@tromey.com>
Sun, 7 Dec 2025 00:55:20 +0000 (18:55 -0600)
committerTom Tromey <tom@tromey.com>
Mon, 9 Feb 2026 15:09:09 +0000 (08:09 -0700)
The buffered stream code is currently in ui-out.h and ui-out.c, which
seems weird because it seems more like a low-level ui-file idea (for
the most part, it does also affect some ui_out).

This patch moves the declarations to a new header file,
buffered-streams.h and the implementation to buffered-streams.c.  This
seems cleaner to me.

Approved-By: Andrew Burgess <aburgess@redhat.com>
gdb/Makefile.in
gdb/buffered-streams.c [new file with mode: 0644]
gdb/buffered-streams.h [new file with mode: 0644]
gdb/cli-out.c
gdb/debuginfod-support.c
gdb/infrun.c
gdb/stack.c
gdb/thread.c
gdb/ui-out.c
gdb/ui-out.h

index 713c0920f6a16efb8e44d94c2e93a587b4f1c1f6..2aa95be968ac014df231011118964366d11ba986 100644 (file)
@@ -1071,6 +1071,7 @@ COMMON_SFILES = \
        breakpoint.c \
        bt-utils.c \
        btrace.c \
+       buffered-streams.c \
        build-id.c \
        buildsym.c \
        c-lang.c \
@@ -1347,6 +1348,7 @@ HFILES_NO_SRCDIR = \
        bsd-uthread.h \
        btrace.h \
        bt-utils.h \
+       buffered-streams.h \
        build-id.h \
        buildsym.h \
        c-exp.h \
diff --git a/gdb/buffered-streams.c b/gdb/buffered-streams.c
new file mode 100644 (file)
index 0000000..a9d3fcf
--- /dev/null
@@ -0,0 +1,155 @@
+/* Copyright (C) 2025, 2026 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/>.  */
+
+#include "buffered-streams.h"
+#include "ui-out.h"
+
+/* See buffered-streams.h.  */
+
+void
+buffer_group::output_unit::flush () const
+{
+  if (!m_msg.empty ())
+    m_stream->puts (m_msg.c_str ());
+
+  if (m_wrap_hint >= 0)
+    m_stream->wrap_here (m_wrap_hint);
+
+  if (m_flush)
+    m_stream->flush ();
+}
+
+/* See buffered-streams.h.  */
+
+void
+buffer_group::write (const char *buf, long length_buf, ui_file *stream)
+{
+  /* Record each line separately.  */
+  for (size_t prev = 0, cur = 0; cur < length_buf; ++cur)
+    if (buf[cur] == '\n' || cur == length_buf - 1)
+      {
+       std::string msg (buf + prev, cur - prev + 1);
+
+       if (m_buffered_output.size () > 0
+           && m_buffered_output.back ().m_wrap_hint == -1
+           && m_buffered_output.back ().m_stream == stream
+           && m_buffered_output.back ().m_msg.size () > 0
+           && m_buffered_output.back ().m_msg.back () != '\n')
+         m_buffered_output.back ().m_msg.append (msg);
+       else
+         m_buffered_output.emplace_back (msg).m_stream = stream;
+       prev = cur + 1;
+      }
+}
+
+/* See buffered-streams.h.  */
+
+void
+buffer_group::wrap_here (int indent, ui_file *stream)
+{
+  m_buffered_output.emplace_back ("", indent).m_stream = stream;
+}
+
+/* See buffered-streams.h.  */
+
+void
+buffer_group::flush_here (ui_file *stream)
+{
+  m_buffered_output.emplace_back ("", -1, true).m_stream = stream;
+}
+
+/* See buffered-streams.h.  */
+
+ui_file *
+get_unbuffered (ui_file *stream)
+{
+  while (true)
+    {
+      buffering_file *buf = dynamic_cast<buffering_file *> (stream);
+
+      if (buf == nullptr)
+       return stream;
+
+      stream = buf->stream ();
+    }
+}
+
+buffered_streams::buffered_streams (buffer_group *group, ui_out *uiout)
+  : m_buffered_stdout (group, gdb_stdout),
+    m_buffered_stderr (group, gdb_stderr),
+    m_buffered_stdlog (group, gdb_stdlog),
+    m_buffered_stdtarg (group, gdb_stdtarg),
+    m_uiout (uiout)
+{
+  gdb_stdout = &m_buffered_stdout;
+  gdb_stderr = &m_buffered_stderr;
+  gdb_stdlog = &m_buffered_stdlog;
+  gdb_stdtarg = &m_buffered_stdtarg;
+
+  ui_file *stream = current_uiout->current_stream ();
+  if (stream != nullptr)
+    {
+      m_buffered_current_uiout.emplace (group, stream);
+      current_uiout->redirect (&(*m_buffered_current_uiout));
+    }
+
+  stream = m_uiout->current_stream ();
+  if (stream != nullptr && current_uiout != m_uiout)
+    {
+      m_buffered_uiout.emplace (group, stream);
+      m_uiout->redirect (&(*m_buffered_uiout));
+    }
+
+  m_buffers_in_place = true;
+}
+
+/* See buffered-streams.h.  */
+
+void
+buffered_streams::remove_buffers ()
+{
+  if (!m_buffers_in_place)
+    return;
+
+  m_buffers_in_place = false;
+
+  gdb_stdout = m_buffered_stdout.stream ();
+  gdb_stderr = m_buffered_stderr.stream ();
+  gdb_stdlog = m_buffered_stdlog.stream ();
+  gdb_stdtarg = m_buffered_stdtarg.stream ();
+
+  if (m_buffered_current_uiout.has_value ())
+    current_uiout->redirect (nullptr);
+
+  if (m_buffered_uiout.has_value ())
+    m_uiout->redirect (nullptr);
+}
+
+buffer_group::buffer_group (ui_out *uiout)
+  : m_buffered_streams (new buffered_streams (this, uiout))
+{ /* Nothing.  */ }
+
+/* See buffered-streams.h.  */
+
+void
+buffer_group::flush () const
+{
+  m_buffered_streams->remove_buffers ();
+
+  for (const output_unit &ou : m_buffered_output)
+    ou.flush ();
+}
diff --git a/gdb/buffered-streams.h b/gdb/buffered-streams.h
new file mode 100644 (file)
index 0000000..0da2d8a
--- /dev/null
@@ -0,0 +1,205 @@
+/* Copyright (C) 2025, 2026 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 GDB_BUFFERED_STREAMS_H
+#define GDB_BUFFERED_STREAMS_H
+
+#include <optional>
+#include "ui-file.h"
+
+struct buffered_streams;
+class ui_out;
+
+/* 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 its 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_BUFFERED_STREAMS_H */
index 0f4dbc7768d04dbf92851e87c5aeb8483c10c580..b1ea9560fcf6f45b7513d7bfb6f39cbdc64bda15 100644 (file)
@@ -27,6 +27,7 @@
 #include "cli/cli-style.h"
 #include "ui.h"
 #include "cli/cli-cmds.h"
+#include "buffered-streams.h"
 
 /* These are the CLI output functions */
 
index 16012f826ce1c1f0157354c55c890c461de9bd76..3da3edc432ddcf5eb932575c60382542c5381686 100644 (file)
@@ -26,6 +26,7 @@
 #include "cli/cli-style.h"
 #include "cli-out.h"
 #include "target.h"
+#include "buffered-streams.h"
 
 /* Set/show debuginfod commands.  */
 static cmd_list_element *set_debuginfod_prefix_list;
index 2abf35deeaf87f9bd308fd47000cd2cd9def4cc2..428359c5580605e3389e15ca391a7026807deece 100644 (file)
@@ -76,6 +76,7 @@
 #include "disasm.h"
 #include "interps.h"
 #include "finish-thread-state.h"
+#include "buffered-streams.h"
 
 /* Prototypes for local functions */
 
index 3e8b6911ef7b51d491ab00974ed0c596326cdc69..aa0257902e19c45c4afbd292320131a5214fe8b3 100644 (file)
@@ -50,6 +50,7 @@
 #include "linespec.h"
 #include "cli/cli-utils.h"
 #include "objfiles.h"
+#include "buffered-streams.h"
 
 #include "symfile.h"
 #include "extension.h"
index 0788bea235a61d6566a68616b2bec726fce8a048..96e3bb7b50f4b48a95853a878fdb3480060b9cae 100644 (file)
@@ -50,6 +50,7 @@
 #include "stack.h"
 #include "interps.h"
 #include "record-full.h"
+#include "buffered-streams.h"
 
 /* Print notices when new threads are attached and detached.  */
 static bool print_thread_events = true;
index 00c2055f492e7cd6a46f6393aee09d470a350b18..8a41d9897fa890598186d24475a4f8a5f8642efe 100644 (file)
@@ -26,6 +26,7 @@
 #include "gdbsupport/format.h"
 #include "cli/cli-style.h"
 #include "diagnostics.h"
+#include "buffered-streams.h"
 
 #include <vector>
 #include <memory>
@@ -847,139 +848,3 @@ ui_out::ui_out (ui_out_flags flags)
 ui_out::~ui_out ()
 {
 }
-
-/* See ui-out.h.  */
-
-void
-buffer_group::output_unit::flush () const
-{
-  if (!m_msg.empty ())
-    m_stream->puts (m_msg.c_str ());
-
-  if (m_wrap_hint >= 0)
-    m_stream->wrap_here (m_wrap_hint);
-
-  if (m_flush)
-    m_stream->flush ();
-}
-
-/* See ui-out.h.  */
-
-void
-buffer_group::write (const char *buf, long length_buf, ui_file *stream)
-{
-  /* Record each line separately.  */
-  for (size_t prev = 0, cur = 0; cur < length_buf; ++cur)
-    if (buf[cur] == '\n' || cur == length_buf - 1)
-      {
-       std::string msg (buf + prev, cur - prev + 1);
-
-       if (m_buffered_output.size () > 0
-           && m_buffered_output.back ().m_wrap_hint == -1
-           && m_buffered_output.back ().m_stream == stream
-           && m_buffered_output.back ().m_msg.size () > 0
-           && m_buffered_output.back ().m_msg.back () != '\n')
-         m_buffered_output.back ().m_msg.append (msg);
-       else
-         m_buffered_output.emplace_back (msg).m_stream = stream;
-       prev = cur + 1;
-      }
-}
-
-/* See ui-out.h.  */
-
-void
-buffer_group::wrap_here (int indent, ui_file *stream)
-{
-  m_buffered_output.emplace_back ("", indent).m_stream = stream;
-}
-
-/* See ui-out.h.  */
-
-void
-buffer_group::flush_here (ui_file *stream)
-{
-  m_buffered_output.emplace_back ("", -1, true).m_stream = stream;
-}
-
-/* See ui-out.h.  */
-
-ui_file *
-get_unbuffered (ui_file *stream)
-{
-  while (true)
-    {
-      buffering_file *buf = dynamic_cast<buffering_file *> (stream);
-
-      if (buf == nullptr)
-       return stream;
-
-      stream = buf->stream ();
-    }
-}
-
-buffered_streams::buffered_streams (buffer_group *group, ui_out *uiout)
-  : m_buffered_stdout (group, gdb_stdout),
-    m_buffered_stderr (group, gdb_stderr),
-    m_buffered_stdlog (group, gdb_stdlog),
-    m_buffered_stdtarg (group, gdb_stdtarg),
-    m_uiout (uiout)
-{
-  gdb_stdout = &m_buffered_stdout;
-  gdb_stderr = &m_buffered_stderr;
-  gdb_stdlog = &m_buffered_stdlog;
-  gdb_stdtarg = &m_buffered_stdtarg;
-
-  ui_file *stream = current_uiout->current_stream ();
-  if (stream != nullptr)
-    {
-      m_buffered_current_uiout.emplace (group, stream);
-      current_uiout->redirect (&(*m_buffered_current_uiout));
-    }
-
-  stream = m_uiout->current_stream ();
-  if (stream != nullptr && current_uiout != m_uiout)
-    {
-      m_buffered_uiout.emplace (group, stream);
-      m_uiout->redirect (&(*m_buffered_uiout));
-    }
-
-  m_buffers_in_place = true;
-}
-
-/* See ui-out.h.  */
-
-void
-buffered_streams::remove_buffers ()
-{
-  if (!m_buffers_in_place)
-    return;
-
-  m_buffers_in_place = false;
-
-  gdb_stdout = m_buffered_stdout.stream ();
-  gdb_stderr = m_buffered_stderr.stream ();
-  gdb_stdlog = m_buffered_stdlog.stream ();
-  gdb_stdtarg = m_buffered_stdtarg.stream ();
-
-  if (m_buffered_current_uiout.has_value ())
-    current_uiout->redirect (nullptr);
-
-  if (m_buffered_uiout.has_value ())
-    m_uiout->redirect (nullptr);
-}
-
-buffer_group::buffer_group (ui_out *uiout)
-  : m_buffered_streams (new buffered_streams (this, uiout))
-{ /* Nothing.  */ }
-
-/* See ui-out.h.  */
-
-void
-buffer_group::flush () const
-{
-  m_buffered_streams->remove_buffers ();
-
-  for (const output_unit &ou : m_buffered_output)
-    ou.flush ();
-}
index ee5e68fa233c42f6d1da9e380620be94fb46067e..69d9910443ecdc9ea8273dffc2ce98873fa5e5c5 100644 (file)
@@ -475,184 +475,4 @@ 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 its 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 */