/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986-2018 Free Software Foundation, Inc.
+ Copyright (C) 1986-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include <ctype.h>
-#include "gdb_wait.h"
+#include "common/gdb_wait.h"
#include "event-top.h"
#include "gdbthread.h"
#include "fnmatch.h"
#include "gdb_usleep.h"
#include "interps.h"
#include "gdb_regex.h"
-#include "job-control.h"
+#include "common/job-control.h"
#include "common/selftest.h"
#include "common/gdb_optional.h"
#include "cp-support.h"
#include <algorithm>
#include "common/pathstuff.h"
#include "cli/cli-style.h"
+#include "common/scope-exit.h"
void (*deprecated_error_begin_hook) (void);
}
\f
-/* Cleanup utilities.
-
- These are not defined in cleanups.c (nor declared in cleanups.h)
- because while they use the "cleanup API" they are not part of the
- "cleanup API". */
-
-/* This function is useful for cleanups.
- Do
-
- foo = xmalloc (...);
- old_chain = make_cleanup (free_current_contents, &foo);
-
- to arrange to free the object thus allocated. */
-
-void
-free_current_contents (void *ptr)
-{
- void **location = (void **) ptr;
-
- if (location == NULL)
- internal_error (__FILE__, __LINE__,
- _("free_current_contents: NULL pointer"));
- if (*location != NULL)
- {
- xfree (*location);
- *location = NULL;
- }
-}
-\f
/* Print a warning message. The first argument STRING is the warning
printf_filtered (_("(%s or %s) [answered %c; "
"input not from terminal]\n"),
y_string, n_string, def_answer);
- gdb_flush (gdb_stdout);
return def_value;
}
/* Column number on the screen where wrap_buffer begins, or 0 if wrapping
is not in effect. */
static int wrap_column;
+
+/* The style applied at the time that wrap_here was called. */
+static ui_file_style wrap_style;
\f
/* Initialize the number of lines per page and chars per line. */
int rows = lines_per_page;
int cols = chars_per_line;
- if (rows <= 0)
- rows = INT_MAX;
+ /* If we get 0 or negative ROWS or COLS, treat as "infinite" size.
+ A negative number can be seen here with the "set width/height"
+ commands and either:
+
+ - the user specified "unlimited", which maps to UINT_MAX, or
+ - the user spedified some number between INT_MAX and UINT_MAX.
+
+ Cap "infinity" to approximately sqrt(INT_MAX) so that we don't
+ overflow in rl_set_screen_size, which multiplies rows and columns
+ to compute the number of characters on the screen. */
+
+ const int sqrt_int_max = INT_MAX >> (sizeof (int) * 8 / 2);
+
+ if (rows <= 0 || rows > sqrt_int_max)
+ {
+ rows = sqrt_int_max;
+ lines_per_page = UINT_MAX;
+ }
- if (cols <= 0)
- cols = INT_MAX;
+ if (cols <= 0 || cols > sqrt_int_max)
+ {
+ cols = sqrt_int_max;
+ chars_per_line = UINT_MAX;
+ }
/* Update Readline's idea of the terminal size. */
rl_set_screen_size (rows, cols);
static ui_file_style applied_style;
-/* The currently desired style. This can differ from the applied
- style when showing the pagination prompt. */
-
-static ui_file_style desired_style;
-
-/* Emit an ANSI style escape for STYLE to the wrap buffer. */
+/* Emit an ANSI style escape for STYLE. If STREAM is nullptr, emit to
+ the wrap buffer; otherwise emit to STREAM. */
static void
-emit_style_escape (const ui_file_style &style)
+emit_style_escape (const ui_file_style &style,
+ struct ui_file *stream = nullptr)
{
- if (applied_style == style)
- return;
applied_style = style;
- wrap_buffer.append (style.to_ansi ());
+ if (stream == nullptr)
+ wrap_buffer.append (style.to_ansi ());
+ else
+ fputs_unfiltered (style.to_ansi ().c_str (), stream);
}
-/* Return true if ANSI escapes can be used on STREAM. */
+/* See utils.h. */
-static bool
+bool
can_emit_style_escape (struct ui_file *stream)
{
if (stream != gdb_stdout
|| !ui_file_isatty (stream))
return false;
const char *term = getenv ("TERM");
+ /* Windows doesn't by default define $TERM, but can support styles
+ regardless. */
+#ifndef _WIN32
if (term == nullptr || !strcmp (term, "dumb"))
return false;
+#else
+ /* But if they do define $TERM, let us behave the same as on Posix
+ platforms, for the benefit of programs which invoke GDB as their
+ back-end. */
+ if (term && !strcmp (term, "dumb"))
+ return false;
+#endif
return true;
}
static void
set_output_style (struct ui_file *stream, const ui_file_style &style)
{
- if (!can_emit_style_escape (stream)
- || style == desired_style)
+ if (!can_emit_style_escape (stream))
return;
- desired_style = style;
+ /* Note that we don't pass STREAM here, because we want to emit to
+ the wrap buffer, not directly to STREAM. */
emit_style_escape (style);
}
{
/* Force the setting, regardless of what we think the setting
might already be. */
- desired_style = ui_file_style ();
- applied_style = desired_style;
- wrap_buffer.append (desired_style.to_ansi ());
+ applied_style = ui_file_style ();
+ wrap_buffer.append (applied_style.to_ansi ());
}
}
bool disable_pagination = pagination_disabled_for_command;
/* Clear the current styling. */
- emit_style_escape (ui_file_style ());
+ if (can_emit_style_escape (gdb_stdout))
+ emit_style_escape (ui_file_style (), gdb_stdout);
if (annotation_level > 1)
printf_unfiltered (("\n\032\032pre-prompt-for-continue\n"));
pagination_disabled_for_command = disable_pagination;
/* Restore the current styling. */
- emit_style_escape (desired_style);
+ if (can_emit_style_escape (gdb_stdout))
+ emit_style_escape (applied_style);
dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */
}
static void
flush_wrap_buffer (struct ui_file *stream)
{
- if (!wrap_buffer.empty ())
+ if (stream == gdb_stdout && !wrap_buffer.empty ())
{
fputs_unfiltered (wrap_buffer.c_str (), stream);
wrap_buffer.clear ();
wrap_indent = "";
else
wrap_indent = indent;
+ wrap_style = applied_style;
}
}
return;
}
+ auto buffer_clearer
+ = make_scope_exit ([&] ()
+ {
+ wrap_buffer.clear ();
+ wrap_column = 0;
+ wrap_indent = "";
+ });
+
/* Go through and output each character. Show line extension
when this is necessary; prompt user for new page when this is
necessary. */
while (*lineptr && *lineptr != '\n')
{
+ int skip_bytes;
+
/* Print a single line. */
if (*lineptr == '\t')
{
chars_printed = ((chars_printed >> 3) + 1) << 3;
lineptr++;
}
+ else if (*lineptr == '\033'
+ && skip_ansi_escape (lineptr, &skip_bytes))
+ {
+ wrap_buffer.append (lineptr, skip_bytes);
+ /* Note that we don't consider this a character, so we
+ don't increment chars_printed here. */
+ lineptr += skip_bytes;
+ }
else
{
wrap_buffer.push_back (*lineptr);
chars_printed = 0;
lines_printed++;
- /* If we aren't actually wrapping, don't output newline --
- if chars_per_line is right, we probably just overflowed
- anyway; if it's wrong, let us keep going. */
if (wrap_column)
{
- emit_style_escape (ui_file_style ());
- flush_wrap_buffer (stream);
+ if (can_emit_style_escape (stream))
+ emit_style_escape (ui_file_style (), stream);
+ /* If we aren't actually wrapping, don't output
+ newline -- if chars_per_line is right, we
+ probably just overflowed anyway; if it's wrong,
+ let us keep going. */
fputc_unfiltered ('\n', stream);
}
+ else
+ flush_wrap_buffer (stream);
/* Possible new page. Note that
PAGINATION_DISABLED_FOR_COMMAND might be set during
if (wrap_column)
{
fputs_unfiltered (wrap_indent, stream);
- emit_style_escape (desired_style);
- flush_wrap_buffer (stream);
+ if (can_emit_style_escape (stream))
+ emit_style_escape (wrap_style, stream);
/* FIXME, this strlen is what prevents wrap_indent from
containing tabs. However, if we recurse to print it
and count its chars, we risk trouble if wrap_indent is
lineptr++;
}
}
+
+ buffer_clearer.release ();
}
void
fputs_styled (const char *linebuffer, const ui_file_style &style,
struct ui_file *stream)
{
- set_output_style (stream, style);
- fputs_maybe_filtered (linebuffer, stream, 1);
- set_output_style (stream, ui_file_style ());
+ /* This just makes it so we emit somewhat fewer escape
+ sequences. */
+ if (style.is_default ())
+ fputs_maybe_filtered (linebuffer, stream, 1);
+ else
+ {
+ set_output_style (stream, style);
+ fputs_maybe_filtered (linebuffer, stream, 1);
+ set_output_style (stream, ui_file_style ());
+ }
}
int
return pid;
}
-/* Helper for make_bpstat_clear_actions_cleanup. */
-
-static void
-do_bpstat_clear_actions_cleanup (void *unused)
-{
- bpstat_clear_actions ();
-}
-
-/* Call bpstat_clear_actions for the case an exception is throw. You should
- discard_cleanups if no exception is caught. */
-
-struct cleanup *
-make_bpstat_clear_actions_cleanup (void)
-{
- return make_cleanup (do_bpstat_clear_actions_cleanup, NULL);
-}
-
/* Substitute all occurences of string FROM by string TO in *STRINGP. *STRINGP
must come from xrealloc-compatible allocator and it may be updated. FROM
needs to be delimited by IS_DIR_SEPARATOR or DIRNAME_SEPARATOR (or be