#include "bt-utils.h"
#include "gdbsupport/buildargv.h"
#include "pager.h"
+#include "run-on-main-thread.h"
void (*deprecated_error_begin_hook) (void);
/* Prototypes for local functions */
-static void vfprintf_maybe_filtered (struct ui_file *, const char *,
- va_list, bool)
- ATTRIBUTE_PRINTF (2, 0);
-
static void set_screen_size (void);
static void set_width (void);
show_sevenbit_strings (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Printing of 8-bit characters "
- "in strings as \\nnn is %s.\n"),
- value);
+ gdb_printf (file, _("Printing of 8-bit characters "
+ "in strings as \\nnn is %s.\n"),
+ value);
}
/* String to be printed before warning messages, if any. */
show_pagination_enabled (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("State of pagination is %s.\n"), value);
+ gdb_printf (file, _("State of pagination is %s.\n"), value);
}
\f
term_state.emplace ();
target_terminal::ours_for_output ();
}
- if (filtered_printing_initialized ())
- gdb_stdout->wrap_here (0); /* Force out any buffered output. */
- gdb_flush (gdb_stdout);
if (warning_pre_print)
- fputs_unfiltered (warning_pre_print, gdb_stderr);
- vfprintf_unfiltered (gdb_stderr, string, args);
- fprintf_unfiltered (gdb_stderr, "\n");
+ gdb_puts (warning_pre_print, gdb_stderr);
+ gdb_vprintf (gdb_stderr, string, args);
+ gdb_printf (gdb_stderr, "\n");
}
}
if (current_ui == NULL)
fputs (msg, stderr);
else
- fputs_unfiltered (msg, gdb_stderr);
+ gdb_puts (msg, gdb_stderr);
abort (); /* ARI: abort */
}
void
warn_cant_dump_core (const char *reason)
{
- fprintf_unfiltered (gdb_stderr,
- _("%s\nUnable to dump core, use `ulimit -c"
- " unlimited' before executing GDB next time.\n"),
- reason);
+ gdb_printf (gdb_stderr,
+ _("%s\nUnable to dump core, use `ulimit -c"
+ " unlimited' before executing GDB next time.\n"),
+ reason);
}
/* Check whether GDB will be able to dump core using the dump_core
bool should_print_backtrace;
};
+/* Return true if the readline callbacks have been initialized for UI.
+ This is always true once GDB is fully initialized, but during the early
+ startup phase this is initially false. */
+
+static bool
+readline_initialized (struct ui *ui)
+{
+ return ui->call_readline != nullptr;
+}
+
/* Report a problem, internal to GDB, to the user. Once the problem
has been reported, and assuming GDB didn't quit, the caller can
either allow execution to resume or throw an error. */
if (problem->should_quit != internal_problem_ask
|| !confirm
|| !filtered_printing_initialized ()
+ || !readline_initialized (current_ui)
|| problem->should_print_backtrace)
- fprintf_unfiltered (gdb_stderr, "%s\n", reason.c_str ());
+ gdb_printf (gdb_stderr, "%s\n", reason.c_str ());
if (problem->should_print_backtrace)
gdb_internal_backtrace ();
/* Default (yes/batch case) is to quit GDB. When in batch mode
this lessens the likelihood of GDB going into an infinite
loop. */
- if (!confirm || !filtered_printing_initialized ())
+ if (!confirm || !filtered_printing_initialized ()
+ || !readline_initialized (current_ui))
quit_p = 1;
else
quit_p = query (_("%s\nQuit this debugging session? "),
else
internal_error (__FILE__, __LINE__, _("bad switch"));
- fputs_unfiltered (_("\nThis is a bug, please report it."), gdb_stderr);
+ gdb_puts (_("\nThis is a bug, please report it."), gdb_stderr);
if (REPORT_BUGS_TO[0])
- fprintf_unfiltered (gdb_stderr, _(" For instructions, see:\n%s."),
- REPORT_BUGS_TO);
- fputs_unfiltered ("\n\n", gdb_stderr);
+ gdb_printf (gdb_stderr, _(" For instructions, see:\n%ps."),
+ styled_string (file_name_style.style (),
+ REPORT_BUGS_TO));
+ gdb_puts ("\n\n", gdb_stderr);
if (problem->should_dump_core == internal_problem_ask)
{
if (!can_dump_core_warn (LIMIT_MAX, reason.c_str ()))
dump_core_p = 0;
- else if (!filtered_printing_initialized ())
+ else if (!filtered_printing_initialized ()
+ || !readline_initialized (current_ui))
dump_core_p = 1;
else
{
print_sys_errmsg (const char *string, int errcode)
{
const char *err = safe_strerror (errcode);
- /* We want anything which was printed on stdout to come out first, before
- this message. */
- gdb_flush (gdb_stdout);
- fprintf_unfiltered (gdb_stderr, "%s: %s.\n", string, err);
+ gdb_printf (gdb_stderr, "%s: %s.\n", string, err);
}
/* Control C eventually causes this to be called, at a convenient time. */
void
maybe_quit (void)
{
+ if (!is_main_thread ())
+ return;
+
if (sync_quit_force_run)
quit ();
target_terminal::scoped_restore_terminal_state term_state;
target_terminal::ours_for_output ();
gdb_stdout->wrap_here (0);
- vfprintf_filtered (gdb_stdout, ctlstr, args);
+ gdb_vprintf (gdb_stdout, ctlstr, args);
- printf_filtered (_("(%s or %s) [answered %c; "
- "input not from terminal]\n"),
- y_string, n_string, def_answer);
+ gdb_printf (_("(%s or %s) [answered %c; "
+ "input not from terminal]\n"),
+ y_string, n_string, def_answer);
return def_value;
}
if (response == NULL) /* C-d */
{
- printf_filtered ("EOF [assumed %c]\n", def_answer);
+ gdb_printf ("EOF [assumed %c]\n", def_answer);
retval = def_value;
break;
}
break;
}
/* Invalid entries are not defaulted and require another selection. */
- printf_filtered (_("Please answer %s or %s.\n"),
- y_string, n_string);
+ gdb_printf (_("Please answer %s or %s.\n"),
+ y_string, n_string);
}
/* Add time spend in this routine to prompt_for_continue_wait_time. */
prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
if (annotation_level > 1)
- printf_filtered (("\n\032\032post-query\n"));
+ gdb_printf (("\n\032\032post-query\n"));
return retval;
}
\f
show_lines_per_page (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file,
- _("Number of lines gdb thinks are in a page is %s.\n"),
- value);
+ gdb_printf (file,
+ _("Number of lines gdb thinks are in a page is %s.\n"),
+ value);
}
/* Number of chars per line or UINT_MAX if line folding is disabled. */
show_chars_per_line (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file,
- _("Number of characters gdb thinks "
- "are in a line is %s.\n"),
- value);
+ gdb_printf (file,
+ _("Number of characters gdb thinks "
+ "are in a line is %s.\n"),
+ value);
}
/* Current count of lines printed on this page, chars on this line. */
/* Buffer and start column of buffered text, for doing smarter word-
wrapping. When someone calls wrap_here(), we start buffering output
- that comes through fputs_filtered(). If we see a newline, we just
+ that comes through gdb_puts(). If we see a newline, we just
spit it out and forget about the wrap_here(). If we see another
wrap_here(), we spit it out and remember the newer one. If we see
the end of the line, we spit out a newline, the indent, and then
}
}
-/* Print input string to gdb_stdout, filtered, with wrap,
- arranging strings in columns of n chars. String can be
- right or left justified in the column. Never prints
- trailing spaces. String should never be longer than
- width. FIXME: this could be useful for the EXAMINE
- command, which currently doesn't tabulate very well. */
+/* Print input string to gdb_stdout arranging strings in columns of n
+ chars. String can be right or left justified in the column. Never
+ prints trailing spaces. String should never be longer than width.
+ FIXME: this could be useful for the EXAMINE command, which
+ currently doesn't tabulate very well. */
void
-puts_filtered_tabular (char *string, int width, int right)
+puts_tabular (char *string, int width, int right)
{
int spaces = 0;
int stringlen;
gdb_assert (chars_per_line > 0);
if (chars_per_line == UINT_MAX)
{
- puts_filtered (string);
- puts_filtered ("\n");
+ gdb_puts (string);
+ gdb_puts ("\n");
return;
}
if (((chars_printed - 1) / width + 2) * width >= chars_per_line)
- puts_filtered ("\n");
+ gdb_puts ("\n");
if (width >= chars_per_line)
width = chars_per_line - 1;
while (spaces--)
spacebuf[spaces] = ' ';
- puts_filtered (spacebuf);
- puts_filtered (string);
+ gdb_puts (spacebuf);
+ gdb_puts (string);
}
{
if (chars_printed > 0)
{
- puts_filtered ("\n");
+ gdb_puts ("\n");
}
}
if (linebuffer == 0)
return;
- /* Don't do any filtering if it is disabled. */
- if (!pagination_enabled
- || pagination_disabled_for_command
- || batch_flag
+ /* Don't do any filtering or wrapping if both are disabled. */
+ if (batch_flag
|| (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)
|| top_level_interpreter () == NULL
|| top_level_interpreter ()->interp_ui_out ()->is_mi_like_p ())
m_wrap_indent = 0;
});
+ /* If the user does "set height 1" then the pager will exhibit weird
+ behavior. This is pathological, though, so don't allow it. */
+ const unsigned int lines_allowed = (lines_per_page > 1
+ ? lines_per_page - 1
+ : 1);
+
/* Go through and output each character. Show line extension
when this is necessary; prompt user for new page when this is
necessary. */
/* Possible new page. Note that PAGINATION_DISABLED_FOR_COMMAND
might be set during this loop, so we must continue to check
it here. */
- if ((lines_printed >= lines_per_page - 1)
- && !pagination_disabled_for_command)
+ if (pagination_enabled
+ && !pagination_disabled_for_command
+ && lines_printed >= lines_allowed)
prompt_for_continue ();
while (*lineptr && *lineptr != '\n')
/* Possible new page. Note that
PAGINATION_DISABLED_FOR_COMMAND might be set during
this loop, so we must continue to check it here. */
- if (lines_printed >= lines_per_page - 1
- && !pagination_disabled_for_command)
+ if (pagination_enabled
+ && !pagination_disabled_for_command
+ && lines_printed >= lines_allowed)
{
prompt_for_continue ();
did_paginate = true;
this->puts (str.c_str ());
}
-void
-fputs_unfiltered (const char *linebuffer, struct ui_file *stream)
+#if GDB_SELF_TEST
+
+/* Test that disabling the pager does not also disable word
+ wrapping. */
+
+static void
+test_pager ()
{
- stream->puts_unfiltered (linebuffer);
+ string_file *strfile = new string_file ();
+ pager_file pager (strfile);
+
+ /* Make sure the pager is disabled. */
+ scoped_restore save_enabled
+ = make_scoped_restore (&pagination_enabled, false);
+ scoped_restore save_disabled
+ = make_scoped_restore (&pagination_disabled_for_command, false);
+ scoped_restore save_batch
+ = make_scoped_restore (&batch_flag, false);
+ scoped_restore save_lines
+ = make_scoped_restore (&lines_per_page, 50);
+ /* Make it easy to word wrap. */
+ scoped_restore save_chars
+ = make_scoped_restore (&chars_per_line, 15);
+ scoped_restore save_printed
+ = make_scoped_restore (&chars_printed, 0);
+
+ pager.puts ("aaaaaaaaaaaa");
+ pager.wrap_here (2);
+ pager.puts ("bbbbbbbbbbbb\n");
+
+ SELF_CHECK (strfile->string () == "aaaaaaaaaaaa\n bbbbbbbbbbbb\n");
}
+#endif /* GDB_SELF_TEST */
+
void
-fputs_filtered (const char *linebuffer, struct ui_file *stream)
+gdb_puts (const char *linebuffer, struct ui_file *stream)
{
stream->puts (linebuffer);
}
struct ui_file *stream)
{
stream->emit_style_escape (style);
- fputs_filtered (linebuffer, stream);
+ gdb_puts (linebuffer, stream);
stream->emit_style_escape (ui_file_style ());
}
/* Output the part before pmatch with current style. */
while (pmatch.rm_so > 0)
{
- fputc_filtered (*str, stream);
+ gdb_putc (*str, stream);
pmatch.rm_so--;
str++;
}
stream->emit_style_escape (highlight_style.style ());
while (n_highlight > 0)
{
- fputc_filtered (*str, stream);
+ gdb_putc (*str, stream);
n_highlight--;
str++;
}
/* Output the trailing part of STR not matching HIGHLIGHT. */
if (*str)
- fputs_filtered (str, stream);
-}
-
-/* Write character C to gdb_stdout using GDB's paging mechanism and return C.
- May return nonlocally. */
-
-int
-putchar_filtered (int c)
-{
- return fputc_filtered (c, gdb_stdout);
-}
-
-int
-fputc_unfiltered (int c, struct ui_file *stream)
-{
- char buf[2];
-
- buf[0] = c;
- buf[1] = 0;
- fputs_unfiltered (buf, stream);
- return c;
-}
-
-int
-fputc_filtered (int c, struct ui_file *stream)
-{
- char buf[2];
-
- buf[0] = c;
- buf[1] = 0;
- fputs_filtered (buf, stream);
- return c;
-}
-
-/* Print a variable number of ARGS using format FORMAT. If this
- information is going to put the amount written (since the last call
- to REINITIALIZE_MORE_FILTER or the last page break) over the page size,
- call prompt_for_continue to get the users permission to continue.
-
- Unlike fprintf, this function does not return a value.
-
- We implement three variants, vfprintf (takes a vararg list and stream),
- fprintf (takes a stream to write on), and printf (the usual).
-
- Note also that this may throw a quit (since prompt_for_continue may
- do so). */
-
-static void
-vfprintf_maybe_filtered (struct ui_file *stream, const char *format,
- va_list args, bool filter)
-{
- stream->vprintf (format, args);
+ gdb_puts (str, stream);
}
-
void
-vfprintf_filtered (struct ui_file *stream, const char *format, va_list args)
+gdb_putc (int c)
{
- vfprintf_maybe_filtered (stream, format, args, true);
+ return gdb_stdout->putc (c);
}
void
-vfprintf_unfiltered (struct ui_file *stream, const char *format, va_list args)
+gdb_putc (int c, struct ui_file *stream)
{
- vfprintf_maybe_filtered (stream, format, args, false);
+ return stream->putc (c);
}
void
-vprintf_filtered (const char *format, va_list args)
+gdb_vprintf (struct ui_file *stream, const char *format, va_list args)
{
- vfprintf_filtered (gdb_stdout, format, args);
-}
-
-void
-vprintf_unfiltered (const char *format, va_list args)
-{
- vfprintf_unfiltered (gdb_stdout, format, args);
+ stream->vprintf (format, args);
}
void
-fprintf_filtered (struct ui_file *stream, const char *format, ...)
+gdb_vprintf (const char *format, va_list args)
{
- va_list args;
-
- va_start (args, format);
- vfprintf_filtered (stream, format, args);
- va_end (args);
+ gdb_stdout->vprintf (format, args);
}
void
-fprintf_unfiltered (struct ui_file *stream, const char *format, ...)
+gdb_printf (struct ui_file *stream, const char *format, ...)
{
va_list args;
va_start (args, format);
- vfprintf_unfiltered (stream, format, args);
+ gdb_vprintf (stream, format, args);
va_end (args);
}
stream->emit_style_escape (style);
va_start (args, format);
- vfprintf_filtered (stream, format, args);
+ gdb_vprintf (stream, format, args);
va_end (args);
stream->emit_style_escape (ui_file_style ());
}
-/* See utils.h. */
-
-void
-vfprintf_styled (struct ui_file *stream, const ui_file_style &style,
- const char *format, va_list args)
-{
- stream->emit_style_escape (style);
- vfprintf_filtered (stream, format, args);
- stream->emit_style_escape (ui_file_style ());
-}
-
void
-printf_filtered (const char *format, ...)
+gdb_printf (const char *format, ...)
{
va_list args;
va_start (args, format);
- vfprintf_filtered (gdb_stdout, format, args);
+ gdb_vprintf (gdb_stdout, format, args);
va_end (args);
}
This one doesn't, and had better not! */
void
-puts_filtered (const char *string)
+gdb_puts (const char *string)
{
- fputs_filtered (string, gdb_stdout);
+ gdb_stdout->puts (string);
}
/* Return a pointer to N spaces and a null. The pointer is good
/* Print N spaces. */
void
-print_spaces_filtered (int n, struct ui_file *stream)
+print_spaces (int n, struct ui_file *stream)
{
- fputs_filtered (n_spaces (n), stream);
+ gdb_puts (n_spaces (n), stream);
}
\f
/* C++/ObjC demangler stuff. */
-/* fprintf_symbol_filtered attempts to demangle NAME, a symbol in language
+/* fprintf_symbol attempts to demangle NAME, a symbol in language
LANG, using demangling args ARG_MODE, and print it filtered to STREAM.
If the name is not mangled, or the language for the name is unknown, or
demangling is off, the name is printed in its "raw" form. */
void
-fprintf_symbol_filtered (struct ui_file *stream, const char *name,
- enum language lang, int arg_mode)
+fprintf_symbol (struct ui_file *stream, const char *name,
+ enum language lang, int arg_mode)
{
if (name != NULL)
{
/* If user wants to see raw output, no problem. */
if (!demangle)
{
- fputs_filtered (name, stream);
+ gdb_puts (name, stream);
}
else
{
gdb::unique_xmalloc_ptr<char> demangled
= language_demangle (language_def (lang), name, arg_mode);
- fputs_filtered (demangled ? demangled.get () : name, stream);
+ gdb_puts (demangled ? demangled.get () : name, stream);
}
}
}
show_debug_timestamp (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("Timestamping debugging messages is %s.\n"),
- value);
+ gdb_printf (file, _("Timestamping debugging messages is %s.\n"),
+ value);
}
\f
selftests::register_test ("gdb_argv_array_view", gdb_argv_as_array_view_test);
selftests::register_test ("strncmp_iw_with_mode",
strncmp_iw_with_mode_tests);
+ selftests::register_test ("pager", test_pager);
#endif
}