diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c
index 31d398cb13b..b6baca94859 100644
--- a/gdb/cli/cli-cmds.c
+++ b/gdb/cli/cli-cmds.c
@@ -843,7 +843,7 @@ echo_command (const char *text, int from_tty)
printf_filtered ("%c", c);
}
- reset_terminal_style (gdb_stdout);
+ gdb_stdout->reset_style ();
/* Force this output to appear now. */
gdb_stdout->wrap_here (0);
diff --git a/gdb/event-top.c b/gdb/event-top.c
index 7de3c91a3a3..41cbe23f189 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -42,6 +42,7 @@
#include "gdbsupport/gdb-sigmask.h"
#include "async-event.h"
#include "bt-utils.h"
+#include "pager.h"
/* readline include files. */
#include "readline/readline.h"
@@ -1300,7 +1301,7 @@ gdb_setup_readline (int editing)
mess it up here. The sync stuff should really go away over
time. */
if (!batch_silent)
- gdb_stdout = new stdio_file (ui->outstream);
+ gdb_stdout = new pager_file (new stdio_file (ui->outstream));
gdb_stderr = new stderr_file (ui->errstream);
gdb_stdlog = new timestamped_file (gdb_stderr);
gdb_stdtarg = gdb_stderr; /* for moment */
diff --git a/gdb/pager.h b/gdb/pager.h
new file mode 100644
index 00000000000..0151a283629
--- /dev/null
+++ b/gdb/pager.h
@@ -0,0 +1,109 @@
+/* Output pager for gdb
+ Copyright (C) 2021, 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 . */
+
+#ifndef GDB_PAGER_H
+#define GDB_PAGER_H
+
+#include "ui-file.h"
+
+/* A ui_file that implements output paging and unfiltered output. */
+
+class pager_file : public ui_file
+{
+public:
+ /* Create a new pager_file. The new object takes ownership of
+ STREAM. */
+ explicit pager_file (ui_file *stream)
+ : m_stream (stream)
+ {
+ }
+
+ DISABLE_COPY_AND_ASSIGN (pager_file);
+
+ void write (const char *buf, long length_buf) override;
+
+ void puts (const char *str) override;
+
+ void write_async_safe (const char *buf, long length_buf) override
+ {
+ m_stream->write_async_safe (buf, length_buf);
+ }
+
+ bool term_out () override
+ {
+ return m_stream->term_out ();
+ }
+
+ bool isatty () override
+ {
+ return m_stream->isatty ();
+ }
+
+ bool can_emit_style_escape () override
+ {
+ return m_stream->can_emit_style_escape ();
+ }
+
+ void emit_style_escape (const ui_file_style &style) override;
+ void reset_style () override;
+
+ void flush () override;
+
+ int fd () const override
+ {
+ return m_stream->fd ();
+ }
+
+ void wrap_here (int indent) override;
+
+ void puts_unfiltered (const char *str) override
+ {
+ flush_wrap_buffer ();
+ m_stream->puts_unfiltered (str);
+ }
+
+private:
+
+ void prompt_for_continue ();
+
+ /* Flush the wrap buffer to STREAM, if necessary. */
+ void flush_wrap_buffer ();
+
+ /* Contains characters which are waiting to be output (they have
+ already been counted in chars_printed). */
+ std::string m_wrap_buffer;
+
+ /* Amount to indent by if the wrap occurs. */
+ int m_wrap_indent = 0;
+
+ /* Column number on the screen where wrap_buffer begins, or 0 if
+ wrapping is not in effect. */
+ int m_wrap_column = 0;
+
+ /* The style applied at the time that wrap_here was called. */
+ ui_file_style m_wrap_style;
+
+ /* The unfiltered output stream. */
+ ui_file_up m_stream;
+
+ /* This is temporarily set when paging. This will cause some
+ methods to change their behavior to ignore the wrap buffer. */
+ bool m_paging = false;
+};
+
+#endif /* GDB_PAGER_H */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 30de1927d39..00a37b2c053 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -2889,7 +2889,7 @@ static void
printf_command (const char *arg, int from_tty)
{
ui_printf (arg, gdb_stdout);
- reset_terminal_style (gdb_stdout);
+ gdb_stdout->reset_style ();
gdb_stdout->wrap_here (0);
gdb_stdout->flush ();
}
diff --git a/gdb/top.c b/gdb/top.c
index afd3c94283d..22850d4474d 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -56,6 +56,7 @@
#include "gdbarch.h"
#include "gdbsupport/pathstuff.h"
#include "cli/cli-style.h"
+#include "pager.h"
/* readline include files. */
#include "readline/readline.h"
@@ -278,7 +279,7 @@ ui::ui (FILE *instream_, FILE *outstream_, FILE *errstream_)
input_fd (fileno (instream)),
input_interactive_p (ISATTY (instream)),
prompt_state (PROMPT_NEEDED),
- m_gdb_stdout (new stdio_file (outstream)),
+ m_gdb_stdout (new pager_file (new stdio_file (outstream))),
m_gdb_stdin (new stdio_file (instream)),
m_gdb_stderr (new stderr_file (errstream)),
m_gdb_stdlog (m_gdb_stderr),
diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 01300d8b74b..22c234a0dc2 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -44,6 +44,7 @@
#include "completer.h"
#include "gdb_curses.h"
#include