/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986-2014 Free Software Foundation, Inc.
+ Copyright (C) 1986-2017 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include "dyn-string.h"
-#include "gdb_assert.h"
#include <ctype.h>
-#include <string.h>
#include "gdb_wait.h"
#include "event-top.h"
-#include "exceptions.h"
#include "gdbthread.h"
#include "fnmatch.h"
#include "gdb_bfd.h"
#endif
#include <signal.h>
-#include "timeval-utils.h"
#include "gdbcmd.h"
#include "serial.h"
#include "bfd.h"
#include "readline/readline.h"
-#include <sys/time.h>
-#include <time.h>
+#include <chrono>
#include "gdb_usleep.h"
#include "interps.h"
Modified in prompt_for_continue and defaulted_query.
Used in report_command_stats. */
-static struct timeval prompt_for_continue_wait_time;
+static std::chrono::steady_clock::duration prompt_for_continue_wait_time;
/* A flag indicating whether to timestamp debugging messages. */
int job_control;
-/* Nonzero means quit immediately if Control-C is typed now, rather
- than waiting until QUIT is executed. Be careful in setting this;
- code which executes with immediate_quit set has to be very careful
- about being able to deal with being interrupted at any time. It is
- almost always better to use QUIT; the only exception I can think of
- is being able to quit out of a system call (using EINTR loses if
- the SIGINT happens between the previous QUIT and the system call).
- To immediately quit in the case in which a SIGINT happens between
- the previous QUIT and setting immediate_quit (desirable anytime we
- expect to block), call QUIT after setting immediate_quit. */
-
-int immediate_quit;
-
/* Nonzero means that strings with character values >0x7F should be printed
as octal escapes. Zero means just print the value (e.g. it's an
international character, and the terminal or window can cope.) */
return make_cleanup (do_freeargv, arg);
}
-static void
-do_dyn_string_delete (void *arg)
-{
- dyn_string_delete ((dyn_string_t) arg);
-}
-
-struct cleanup *
-make_cleanup_dyn_string_delete (dyn_string_t arg)
-{
- return make_cleanup (do_dyn_string_delete, arg);
-}
-
-static void
-do_bfd_close_cleanup (void *arg)
-{
- gdb_bfd_unref (arg);
-}
-
-struct cleanup *
-make_cleanup_bfd_unref (bfd *abfd)
-{
- return make_cleanup (do_bfd_close_cleanup, abfd);
-}
-
-static void
-do_close_cleanup (void *arg)
-{
- int *fd = arg;
-
- close (*fd);
-}
-
-struct cleanup *
-make_cleanup_close (int fd)
-{
- int *saved_fd = xmalloc (sizeof (fd));
-
- *saved_fd = fd;
- return make_cleanup_dtor (do_close_cleanup, saved_fd, xfree);
-}
-
/* Helper function which does the work for make_cleanup_fclose. */
static void
do_fclose_cleanup (void *arg)
{
- FILE *file = arg;
+ FILE *file = (FILE *) arg;
fclose (file);
}
static void
do_obstack_free (void *arg)
{
- struct obstack *ob = arg;
+ struct obstack *ob = (struct obstack *) arg;
obstack_free (ob, NULL);
}
return make_cleanup (do_obstack_free, obstack);
}
-static void
-do_ui_file_delete (void *arg)
-{
- ui_file_delete (arg);
-}
-
-struct cleanup *
-make_cleanup_ui_file_delete (struct ui_file *arg)
-{
- return make_cleanup (do_ui_file_delete, arg);
-}
-
/* Helper function for make_cleanup_ui_out_redirect_pop. */
static void
do_ui_out_redirect_pop (void *arg)
{
- struct ui_out *uiout = arg;
+ struct ui_out *uiout = (struct ui_out *) arg;
- if (ui_out_redirect (uiout, NULL) < 0)
- warning (_("Cannot restore redirection of the current output protocol"));
+ uiout->redirect (NULL);
}
/* Return a new cleanup that pops the last redirection by ui_out_redirect
static void
do_free_section_addr_info (void *arg)
{
- free_section_addr_info (arg);
+ free_section_addr_info ((struct section_addr_info *) arg);
}
struct cleanup *
static void
restore_integer (void *p)
{
- struct restore_integer_closure *closure = p;
+ struct restore_integer_closure *closure
+ = (struct restore_integer_closure *) p;
*(closure->variable) = closure->value;
}
struct cleanup *
make_cleanup_restore_integer (int *variable)
{
- struct restore_integer_closure *c =
- xmalloc (sizeof (struct restore_integer_closure));
+ struct restore_integer_closure *c = XNEW (struct restore_integer_closure);
c->variable = variable;
c->value = *variable;
static void
do_unpush_target (void *arg)
{
- struct target_ops *ops = arg;
+ struct target_ops *ops = (struct target_ops *) arg;
unpush_target (ops);
}
return make_cleanup (do_unpush_target, ops);
}
-/* Helper for make_cleanup_htab_delete compile time checking the types. */
-
-static void
-do_htab_delete_cleanup (void *htab_voidp)
-{
- htab_t htab = htab_voidp;
-
- htab_delete (htab);
-}
-
-/* Return a new cleanup that deletes HTAB. */
-
-struct cleanup *
-make_cleanup_htab_delete (htab_t htab)
-{
- return make_cleanup (do_htab_delete_cleanup, htab);
-}
-
-struct restore_ui_file_closure
-{
- struct ui_file **variable;
- struct ui_file *value;
-};
-
-static void
-do_restore_ui_file (void *p)
-{
- struct restore_ui_file_closure *closure = p;
-
- *(closure->variable) = closure->value;
-}
-
-/* Remember the current value of *VARIABLE and make it restored when
- the cleanup is run. */
-
-struct cleanup *
-make_cleanup_restore_ui_file (struct ui_file **variable)
-{
- struct restore_ui_file_closure *c = XNEW (struct restore_ui_file_closure);
-
- c->variable = variable;
- c->value = *variable;
-
- return make_cleanup_dtor (do_restore_ui_file, (void *) c, xfree);
-}
-
/* Helper for make_cleanup_value_free_to_mark. */
static void
static void
do_value_free (void *value)
{
- value_free (value);
+ value_free ((struct value *) value);
}
/* Free VALUE. */
static void
do_free_so (void *arg)
{
- struct so_list *so = arg;
+ struct so_list *so = (struct so_list *) arg;
free_so (so);
}
static void
do_restore_current_language (void *p)
{
- enum language saved_lang = (uintptr_t) p;
+ enum language saved_lang = (enum language) (uintptr_t) p;
set_language (saved_lang);
}
(void *) (uintptr_t) saved_lang);
}
+/* Helper function for make_cleanup_clear_parser_state. */
+
+static void
+do_clear_parser_state (void *ptr)
+{
+ struct parser_state **p = (struct parser_state **) ptr;
+
+ *p = NULL;
+}
+
+/* Clean (i.e., set to NULL) the parser state variable P. */
+
+struct cleanup *
+make_cleanup_clear_parser_state (struct parser_state **p)
+{
+ return make_cleanup (do_clear_parser_state, (void *) p);
+}
+
/* This function is useful for cleanups.
Do
void
free_current_contents (void *ptr)
{
- void **location = ptr;
+ void **location = (void **) ptr;
if (location == NULL)
internal_error (__FILE__, __LINE__,
(*deprecated_warning_hook) (string, args);
else
{
- target_terminal_ours ();
- wrap_here (""); /* Force out any buffered output. */
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
+ if (target_supports_terminal_ours ())
+ {
+ make_cleanup_restore_target_terminal ();
+ target_terminal_ours_for_output ();
+ }
+ if (filtered_printing_initialized ())
+ wrap_here (""); /* 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");
- va_end (args);
- }
-}
-/* Print a warning message.
- The first argument STRING is the warning message, used as a fprintf string,
- and the remaining args are passed as arguments to it.
- The primary difference between warnings and errors is that a warning
- does not force the return to command level. */
-
-void
-warning (const char *string, ...)
-{
- va_list args;
-
- va_start (args, string);
- vwarning (string, args);
- va_end (args);
+ do_cleanups (old_chain);
+ }
}
/* Print an error message and return to command level.
}
void
-error (const char *string, ...)
+error_stream (const string_file &stream)
{
- va_list args;
-
- va_start (args, string);
- throw_verror (GENERIC_ERROR, string, args);
- va_end (args);
+ error (("%s"), stream.c_str ());
}
-/* Print an error message and quit.
- The first argument STRING is the error message, used as a fprintf string,
- and the remaining args are passed as arguments to it. */
-
-void
-vfatal (const char *string, va_list args)
-{
- throw_vfatal (string, args);
-}
-
-void
-fatal (const char *string, ...)
-{
- va_list args;
-
- va_start (args, string);
- throw_vfatal (string, args);
- va_end (args);
-}
+/* Emit a message and abort. */
-void
-error_stream (struct ui_file *stream)
+static void ATTRIBUTE_NORETURN
+abort_with_message (const char *msg)
{
- char *message = ui_file_xstrdup (stream, NULL);
+ if (gdb_stderr == NULL)
+ fputs (msg, stderr);
+ else
+ fputs_unfiltered (msg, gdb_stderr);
- make_cleanup (xfree, message);
- error (("%s"), message);
+ abort (); /* NOTE: GDB has only three calls to abort(). */
}
/* Dump core trying to increase the core soft limit to hard limit first. */
-static void
+void
dump_core (void)
{
#ifdef HAVE_SETRLIMIT
}
/* Check whether GDB will be able to dump core using the dump_core
- function. */
+ function. Returns zero if GDB cannot or should not dump core.
+ If LIMIT_KIND is LIMIT_CUR the user's soft limit will be respected.
+ If LIMIT_KIND is LIMIT_MAX only the hard limit will be respected. */
-static int
-can_dump_core (const char *reason)
+int
+can_dump_core (enum resource_limit_kind limit_kind)
{
#ifdef HAVE_GETRLIMIT
struct rlimit rlim;
if (getrlimit (RLIMIT_CORE, &rlim) != 0)
return 1;
- if (rlim.rlim_max == 0)
+ switch (limit_kind)
{
- fprintf_unfiltered (gdb_stderr,
- _("%s\nUnable to dump core, use `ulimit -c"
- " unlimited' before executing GDB next time.\n"),
- reason);
- return 0;
+ case LIMIT_CUR:
+ if (rlim.rlim_cur == 0)
+ return 0;
+
+ case LIMIT_MAX:
+ if (rlim.rlim_max == 0)
+ return 0;
}
#endif /* HAVE_GETRLIMIT */
return 1;
}
+/* Print a warning that we cannot dump core. */
+
+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);
+}
+
+/* Check whether GDB will be able to dump core using the dump_core
+ function, and print a warning if we cannot. */
+
+static int
+can_dump_core_warn (enum resource_limit_kind limit_kind,
+ const char *reason)
+{
+ int core_dump_allowed = can_dump_core (limit_kind);
+
+ if (!core_dump_allowed)
+ warn_cant_dump_core (reason);
+
+ return core_dump_allowed;
+}
+
/* Allow the user to configure the debugger behavior with respect to
what to do when an internal problem is detected. */
struct internal_problem
{
const char *name;
+ int user_settable_should_quit;
const char *should_quit;
+ int user_settable_should_dump_core;
const char *should_dump_core;
};
break;
case 1:
dejavu = 2;
- fputs_unfiltered (msg, gdb_stderr);
- abort (); /* NOTE: GDB has only three calls to abort(). */
+ abort_with_message (msg);
default:
dejavu = 3;
/* Newer GLIBC versions put the warn_unused_result attribute
}
}
- /* Try to get the message out and at the start of a new line. */
- target_terminal_ours ();
- begin_line ();
-
/* Create a string containing the full error/warning message. Need
to call query with this full string, as otherwize the reason
(error/warning) and question become separated. Format using a
make_cleanup (xfree, reason);
}
+ /* Fall back to abort_with_message if gdb_stderr is not set up. */
+ if (gdb_stderr == NULL)
+ {
+ fputs (reason, stderr);
+ abort_with_message ("\n");
+ }
+
+ /* Try to get the message out and at the start of a new line. */
+ if (target_supports_terminal_ours ())
+ {
+ make_cleanup_restore_target_terminal ();
+ target_terminal_ours_for_output ();
+ }
+ if (filtered_printing_initialized ())
+ begin_line ();
+
+ /* Emit the message unless query will emit it below. */
+ if (problem->should_quit != internal_problem_ask
+ || !confirm
+ || !filtered_printing_initialized ())
+ fprintf_unfiltered (gdb_stderr, "%s\n", reason);
+
if (problem->should_quit == internal_problem_ask)
{
/* 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)
- {
- /* Emit the message and quit. */
- fputs_unfiltered (reason, gdb_stderr);
- fputs_unfiltered ("\n", gdb_stderr);
- quit_p = 1;
- }
+ if (!confirm || !filtered_printing_initialized ())
+ quit_p = 1;
else
quit_p = query (_("%s\nQuit this debugging session? "), reason);
}
else
internal_error (__FILE__, __LINE__, _("bad switch"));
+ fputs_unfiltered (_("\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);
+
if (problem->should_dump_core == internal_problem_ask)
{
- if (!can_dump_core (reason))
+ if (!can_dump_core_warn (LIMIT_MAX, reason))
dump_core_p = 0;
+ else if (!filtered_printing_initialized ())
+ dump_core_p = 1;
else
{
/* Default (yes/batch case) is to dump core. This leaves a GDB
}
}
else if (problem->should_dump_core == internal_problem_yes)
- dump_core_p = can_dump_core (reason);
+ dump_core_p = can_dump_core_warn (LIMIT_MAX, reason);
else if (problem->should_dump_core == internal_problem_no)
dump_core_p = 0;
else
}
static struct internal_problem internal_error_problem = {
- "internal-error", internal_problem_ask, internal_problem_ask
+ "internal-error", 1, internal_problem_ask, 1, internal_problem_ask
};
void
internal_verror (const char *file, int line, const char *fmt, va_list ap)
{
internal_vproblem (&internal_error_problem, file, line, fmt, ap);
- fatal (_("Command aborted."));
+ throw_quit (_("Command aborted."));
}
+static struct internal_problem internal_warning_problem = {
+ "internal-warning", 1, internal_problem_ask, 1, internal_problem_ask
+};
+
void
-internal_error (const char *file, int line, const char *string, ...)
+internal_vwarning (const char *file, int line, const char *fmt, va_list ap)
{
- va_list ap;
-
- va_start (ap, string);
- internal_verror (file, line, string, ap);
- va_end (ap);
+ internal_vproblem (&internal_warning_problem, file, line, fmt, ap);
}
-static struct internal_problem internal_warning_problem = {
- "internal-warning", internal_problem_ask, internal_problem_ask
+static struct internal_problem demangler_warning_problem = {
+ "demangler-warning", 1, internal_problem_ask, 0, internal_problem_no
};
void
-internal_vwarning (const char *file, int line, const char *fmt, va_list ap)
+demangler_vwarning (const char *file, int line, const char *fmt, va_list ap)
{
- internal_vproblem (&internal_warning_problem, file, line, fmt, ap);
+ internal_vproblem (&demangler_warning_problem, file, line, fmt, ap);
}
void
-internal_warning (const char *file, int line, const char *string, ...)
+demangler_warning (const char *file, int line, const char *string, ...)
{
va_list ap;
va_start (ap, string);
- internal_vwarning (file, line, string, ap);
+ demangler_vwarning (file, line, string, ap);
va_end (ap);
}
char *set_doc;
char *show_doc;
- set_cmd_list = xmalloc (sizeof (*set_cmd_list));
- show_cmd_list = xmalloc (sizeof (*set_cmd_list));
+ set_cmd_list = XNEW (struct cmd_list_element *);
+ show_cmd_list = XNEW (struct cmd_list_element *);
*set_cmd_list = NULL;
*show_cmd_list = NULL;
(char *) NULL),
0/*allow-unknown*/, &maintenance_show_cmdlist);
- set_doc = xstrprintf (_("Set whether GDB should quit "
- "when an %s is detected"),
- problem->name);
- show_doc = xstrprintf (_("Show whether GDB will quit "
- "when an %s is detected"),
- problem->name);
- add_setshow_enum_cmd ("quit", class_maintenance,
- internal_problem_modes,
- &problem->should_quit,
- set_doc,
- show_doc,
- NULL, /* help_doc */
- NULL, /* setfunc */
- NULL, /* showfunc */
- set_cmd_list,
- show_cmd_list);
-
- xfree (set_doc);
- xfree (show_doc);
-
- set_doc = xstrprintf (_("Set whether GDB should create a core "
- "file of GDB when %s is detected"),
- problem->name);
- show_doc = xstrprintf (_("Show whether GDB will create a core "
- "file of GDB when %s is detected"),
- problem->name);
- add_setshow_enum_cmd ("corefile", class_maintenance,
- internal_problem_modes,
- &problem->should_dump_core,
- set_doc,
- show_doc,
- NULL, /* help_doc */
- NULL, /* setfunc */
- NULL, /* showfunc */
- set_cmd_list,
- show_cmd_list);
+ if (problem->user_settable_should_quit)
+ {
+ set_doc = xstrprintf (_("Set whether GDB should quit "
+ "when an %s is detected"),
+ problem->name);
+ show_doc = xstrprintf (_("Show whether GDB will quit "
+ "when an %s is detected"),
+ problem->name);
+ add_setshow_enum_cmd ("quit", class_maintenance,
+ internal_problem_modes,
+ &problem->should_quit,
+ set_doc,
+ show_doc,
+ NULL, /* help_doc */
+ NULL, /* setfunc */
+ NULL, /* showfunc */
+ set_cmd_list,
+ show_cmd_list);
+
+ xfree (set_doc);
+ xfree (show_doc);
+ }
- xfree (set_doc);
- xfree (show_doc);
+ if (problem->user_settable_should_dump_core)
+ {
+ set_doc = xstrprintf (_("Set whether GDB should create a core "
+ "file of GDB when %s is detected"),
+ problem->name);
+ show_doc = xstrprintf (_("Show whether GDB will create a core "
+ "file of GDB when %s is detected"),
+ problem->name);
+ add_setshow_enum_cmd ("corefile", class_maintenance,
+ internal_problem_modes,
+ &problem->should_dump_core,
+ set_doc,
+ show_doc,
+ NULL, /* help_doc */
+ NULL, /* setfunc */
+ NULL, /* showfunc */
+ set_cmd_list,
+ show_cmd_list);
+
+ xfree (set_doc);
+ xfree (show_doc);
+ }
}
/* Return a newly allocated string, containing the PREFIX followed
void
quit (void)
{
+ struct ui *ui = current_ui;
+
+ if (sync_quit_force_run)
+ {
+ sync_quit_force_run = 0;
+ quit_force (NULL, 0);
+ }
+
#ifdef __MSDOS__
/* No steenking SIGINT will ever be coming our way when the
program is resumed. Don't lie. */
- fatal ("Quit");
+ throw_quit ("Quit");
#else
if (job_control
/* If there is no terminal switching for this target, then we can't
possibly get screwed by the lack of job control. */
- || current_target.to_terminal_ours == NULL)
- fatal ("Quit");
+ || !target_supports_terminal_ours ())
+ throw_quit ("Quit");
else
- fatal ("Quit (expect signal SIGINT when the program is resumed)");
+ throw_quit ("Quit (expect signal SIGINT when the program is resumed)");
#endif
}
+/* See defs.h. */
+
+void
+maybe_quit (void)
+{
+ if (sync_quit_force_run)
+ quit ();
+
+ quit_handler ();
+
+ if (deprecated_interactive_hook)
+ deprecated_interactive_hook ();
+}
+
\f
/* Called when a memory allocation fails, with the number of bytes of
memory requested in SIZE. */
/* Print a host address. */
void
-gdb_print_host_address (const void *addr, struct ui_file *stream)
+gdb_print_host_address_1 (const void *addr, struct ui_file *stream)
{
fprintf_filtered (stream, "%s", host_address_to_string (addr));
}
+
+/* See utils.h. */
+
+char *
+make_hex_string (const gdb_byte *data, size_t length)
+{
+ char *result = (char *) xmalloc (length * 2 + 1);
+ char *p;
+ size_t i;
+
+ p = result;
+ for (i = 0; i < length; ++i)
+ p += xsnprintf (p, 3, "%02x", data[i]);
+ *p = '\0';
+ return result;
+}
+
\f
/* A cleanup function that calls regfree. */
static void
do_regfree_cleanup (void *r)
{
- regfree (r);
+ regfree ((regex_t *) r);
}
/* Create a new cleanup that frees the compiled regular expression R. */
get_regcomp_error (int code, regex_t *rx)
{
size_t length = regerror (code, rx, NULL, 0);
- char *result = xmalloc (length);
+ char *result = (char *) xmalloc (length);
regerror (code, rx, result, length);
return result;
return make_regfree_cleanup (pattern);
}
+/* A cleanup that simply calls ui_unregister_input_event_handler. */
+
+static void
+ui_unregister_input_event_handler_cleanup (void *ui)
+{
+ ui_unregister_input_event_handler ((struct ui *) ui);
+}
+
+/* Set up to handle input. */
+
+static struct cleanup *
+prepare_to_handle_input (void)
+{
+ struct cleanup *old_chain;
+
+ old_chain = make_cleanup_restore_target_terminal ();
+ target_terminal_ours ();
+
+ ui_register_input_event_handler (current_ui);
+ if (current_ui->prompt_state == PROMPT_BLOCKED)
+ make_cleanup (ui_unregister_input_event_handler_cleanup, current_ui);
+
+ make_cleanup_override_quit_handler (default_quit_handler);
+
+ return old_chain;
+}
+
\f
/* This function supports the query, nquery, and yquery functions.
static int ATTRIBUTE_PRINTF (1, 0)
defaulted_query (const char *ctlstr, const char defchar, va_list args)
{
- int answer;
int ans2;
int retval;
int def_value;
char def_answer, not_def_answer;
- char *y_string, *n_string, *question;
- /* Used to add duration we waited for user to respond to
- prompt_for_continue_wait_time. */
- struct timeval prompt_started, prompt_ended, prompt_delta;
+ char *y_string, *n_string, *question, *prompt;
+ struct cleanup *old_chain;
/* Set up according to which answer is the default. */
if (defchar == '\0')
question we're asking, and then answer the default automatically. This
way, important error messages don't get lost when talking to GDB
over a pipe. */
- if (! input_from_terminal_p ())
+ if (current_ui->instream != current_ui->stdin_stream
+ || !input_interactive_p (current_ui)
+ /* Restrict queries to the main UI. */
+ || current_ui != main_ui)
{
+ old_chain = make_cleanup_restore_target_terminal ();
+
+ target_terminal_ours_for_output ();
wrap_here ("");
vfprintf_filtered (gdb_stdout, ctlstr, args);
y_string, n_string, def_answer);
gdb_flush (gdb_stdout);
+ do_cleanups (old_chain);
return def_value;
}
if (deprecated_query_hook)
{
- return deprecated_query_hook (ctlstr, args);
+ int res;
+
+ old_chain = make_cleanup_restore_target_terminal ();
+ res = deprecated_query_hook (ctlstr, args);
+ do_cleanups (old_chain);
+ return res;
}
/* Format the question outside of the loop, to avoid reusing args. */
question = xstrvprintf (ctlstr, args);
+ old_chain = make_cleanup (xfree, question);
+ prompt = xstrprintf (_("%s%s(%s or %s) %s"),
+ annotation_level > 1 ? "\n\032\032pre-query\n" : "",
+ question, y_string, n_string,
+ annotation_level > 1 ? "\n\032\032query\n" : "");
+ make_cleanup (xfree, prompt);
+
+ /* Used to add duration we waited for user to respond to
+ prompt_for_continue_wait_time. */
+ using namespace std::chrono;
+ steady_clock::time_point prompt_started = steady_clock::now ();
- /* Used for calculating time spend waiting for user. */
- gettimeofday (&prompt_started, NULL);
+ prepare_to_handle_input ();
while (1)
{
- wrap_here (""); /* Flush any buffered output. */
- gdb_flush (gdb_stdout);
-
- if (annotation_level > 1)
- printf_filtered (("\n\032\032pre-query\n"));
+ char *response, answer;
- fputs_filtered (question, gdb_stdout);
- printf_filtered (_("(%s or %s) "), y_string, n_string);
-
- if (annotation_level > 1)
- printf_filtered (("\n\032\032query\n"));
-
- wrap_here ("");
gdb_flush (gdb_stdout);
+ response = gdb_readline_wrapper (prompt);
- answer = fgetc (stdin);
-
- /* We expect fgetc to block until a character is read. But
- this may not be the case if the terminal was opened with
- the NONBLOCK flag. In that case, if there is nothing to
- read on stdin, fgetc returns EOF, but also sets the error
- condition flag on stdin and errno to EAGAIN. With a true
- EOF, stdin's error condition flag is not set.
-
- A situation where this behavior was observed is a pseudo
- terminal on AIX. */
- while (answer == EOF && ferror (stdin) && errno == EAGAIN)
- {
- /* Not a real EOF. Wait a little while and try again until
- we read something. */
- clearerr (stdin);
- gdb_usleep (10000);
- answer = fgetc (stdin);
- }
-
- clearerr (stdin); /* in case of C-d */
- if (answer == EOF) /* C-d */
+ if (response == NULL) /* C-d */
{
printf_filtered ("EOF [assumed %c]\n", def_answer);
retval = def_value;
break;
}
- /* Eat rest of input line, to EOF or newline. */
- if (answer != '\n')
- do
- {
- ans2 = fgetc (stdin);
- clearerr (stdin);
- }
- while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
+
+ answer = response[0];
+ xfree (response);
if (answer >= 'a')
answer -= 040;
specify the required input or have it default by entering
nothing. */
if (answer == def_answer
- || (defchar != '\0' &&
- (answer == '\n' || answer == '\r' || answer == EOF)))
+ || (defchar != '\0' && answer == '\0'))
{
retval = def_value;
break;
}
/* Add time spend in this routine to prompt_for_continue_wait_time. */
- gettimeofday (&prompt_ended, NULL);
- timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
- timeval_add (&prompt_for_continue_wait_time,
- &prompt_for_continue_wait_time, &prompt_delta);
+ prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
- xfree (question);
if (annotation_level > 1)
printf_filtered (("\n\032\032post-query\n"));
+ do_cleanups (old_chain);
return retval;
}
\f
\f
/* Print the character C on STREAM as part of the contents of a literal
string whose delimiter is QUOTER. Note that this routine should only
- be call for printing things which are independent of the language
- of the program being debugged. */
+ be called for printing things which are independent of the language
+ of the program being debugged.
+
+ printchar will normally escape backslashes and instances of QUOTER. If
+ QUOTER is 0, printchar won't escape backslashes or any quoting character.
+ As a side effect, if you pass the backslash character as the QUOTER,
+ printchar will escape backslashes as usual, but not any other quoting
+ character. */
static void
printchar (int c, void (*do_fputs) (const char *, struct ui_file *),
}
else
{
- if (c == '\\' || c == quoter)
+ if (quoter != 0 && (c == '\\' || c == quoter))
do_fputs ("\\", stream);
do_fprintf (stream, "%c", c);
}
/* String to indent by if the wrap occurs. Must not be NULL if wrap_column
is non-zero. */
-static char *wrap_indent;
+static const char *wrap_indent;
/* Column number on the screen where wrap_buffer begins, or 0 if wrapping
is not in effect. */
static int wrap_column;
\f
-/* Inialize the number of lines per page and chars per line. */
+/* Initialize the number of lines per page and chars per line. */
void
init_page_info (void)
Only try to use tgetnum function if rl_get_screen_size
did not return a useful value. */
if (((rows <= 0) && (tgetnum ("li") < 0))
- /* Also disable paging if inside EMACS. */
- || getenv ("EMACS"))
+ /* Also disable paging if inside Emacs. $EMACS was used
+ before Emacs v25.1, $INSIDE_EMACS is used since then. */
+ || getenv ("EMACS") || getenv ("INSIDE_EMACS"))
{
/* The number of lines per page is not mentioned in the terminal
description or EMACS evironment variable is set. This probably
#endif
}
+ /* We handle SIGWINCH ourselves. */
+ rl_catch_sigwinch = 0;
+
set_screen_size ();
set_width ();
}
+/* Return nonzero if filtered printing is initialized. */
+int
+filtered_printing_initialized (void)
+{
+ return wrap_buffer != NULL;
+}
+
/* Helper for make_cleanup_restore_page_info. */
static void
set_screen_size ();
}
+/* See utils.h. */
+
+void
+set_screen_width_and_height (int width, int height)
+{
+ lines_per_page = height;
+ chars_per_line = width;
+
+ set_screen_size ();
+ set_width ();
+}
+
/* Wait, so the user can read what's on the screen. Prompt the user
- to continue by pressing RETURN. */
+ to continue by pressing RETURN. 'q' is also provided because
+ telling users what to do in the prompt is more user-friendly than
+ expecting them to think of Ctrl-C/SIGINT. */
static void
prompt_for_continue (void)
{
char *ignore;
char cont_prompt[120];
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
/* Used to add duration we waited for user to respond to
prompt_for_continue_wait_time. */
- struct timeval prompt_started, prompt_ended, prompt_delta;
-
- gettimeofday (&prompt_started, NULL);
+ using namespace std::chrono;
+ steady_clock::time_point prompt_started = steady_clock::now ();
if (annotation_level > 1)
printf_unfiltered (("\n\032\032pre-prompt-for-continue\n"));
if (annotation_level > 1)
strcat (cont_prompt, "\n\032\032prompt-for-continue\n");
- /* We must do this *before* we call gdb_readline, else it will eventually
- call us -- thinking that we're trying to print beyond the end of the
- screen. */
+ /* We must do this *before* we call gdb_readline_wrapper, else it
+ will eventually call us -- thinking that we're trying to print
+ beyond the end of the screen. */
reinitialize_more_filter ();
- immediate_quit++;
- QUIT;
- /* On a real operating system, the user can quit with SIGINT.
- But not on GO32.
-
- 'q' is provided on all systems so users don't have to change habits
- from system to system, and because telling them what to do in
- the prompt is more user-friendly than expecting them to think of
- SIGINT. */
- /* Call readline, not gdb_readline, because GO32 readline handles control-C
- whereas control-C to gdb_readline will cause the user to get dumped
- out to DOS. */
+ prepare_to_handle_input ();
+
+ /* Call gdb_readline_wrapper, not readline, in order to keep an
+ event loop running. */
ignore = gdb_readline_wrapper (cont_prompt);
+ make_cleanup (xfree, ignore);
/* Add time spend in this routine to prompt_for_continue_wait_time. */
- gettimeofday (&prompt_ended, NULL);
- timeval_sub (&prompt_delta, &prompt_ended, &prompt_started);
- timeval_add (&prompt_for_continue_wait_time,
- &prompt_for_continue_wait_time, &prompt_delta);
+ prompt_for_continue_wait_time += steady_clock::now () - prompt_started;
if (annotation_level > 1)
printf_unfiltered (("\n\032\032post-prompt-for-continue\n"));
- if (ignore)
+ if (ignore != NULL)
{
char *p = ignore;
while (*p == ' ' || *p == '\t')
++p;
if (p[0] == 'q')
- quit ();
- xfree (ignore);
+ /* Do not call quit here; there is no possibility of SIGINT. */
+ throw_quit ("Quit");
}
- immediate_quit--;
/* Now we have to do this again, so that GDB will know that it doesn't
need to save the ---Type <return>--- line at the top of the screen. */
reinitialize_more_filter ();
dont_repeat (); /* Forget prev cmd -- CR won't repeat it. */
+
+ do_cleanups (old_chain);
}
-/* Initalize timer to keep track of how long we waited for the user. */
+/* Initialize timer to keep track of how long we waited for the user. */
void
reset_prompt_for_continue_wait_time (void)
{
- static const struct timeval zero_timeval = { 0 };
+ using namespace std::chrono;
- prompt_for_continue_wait_time = zero_timeval;
+ prompt_for_continue_wait_time = steady_clock::duration::zero ();
}
/* Fetch the cumulative time spent in prompt_for_continue. */
-struct timeval
-get_prompt_for_continue_wait_time (void)
+std::chrono::steady_clock::duration
+get_prompt_for_continue_wait_time ()
{
return prompt_for_continue_wait_time;
}
used to force out output from the wrap_buffer. */
void
-wrap_here (char *indent)
+wrap_here (const char *indent)
{
/* This should have been allocated, but be paranoid anyway. */
if (!wrap_buffer)
if (right)
spaces += width - stringlen;
- spacebuf = alloca (spaces + 1);
+ spacebuf = (char *) alloca (spaces + 1);
spacebuf[spaces] = '\0';
while (spaces--)
spacebuf[spaces] = ' ';
|| batch_flag
|| (lines_per_page == UINT_MAX && chars_per_line == UINT_MAX)
|| top_level_interpreter () == NULL
- || ui_out_is_mi_like_p (interp_ui_out (top_level_interpreter ())))
+ || interp_ui_out (top_level_interpreter ())->is_mi_like_p ())
{
fputs_unfiltered (linebuffer, stream);
return;
old_cleanups = make_cleanup (xfree, linebuffer);
if (debug_timestamp && stream == gdb_stdlog)
{
- struct timeval tm;
- char *timestamp;
+ using namespace std::chrono;
int len, need_nl;
- gettimeofday (&tm, NULL);
+ steady_clock::time_point now = steady_clock::now ();
+ seconds s = duration_cast<seconds> (now.time_since_epoch ());
+ microseconds us = duration_cast<microseconds> (now.time_since_epoch () - s);
len = strlen (linebuffer);
need_nl = (len > 0 && linebuffer[len - 1] != '\n');
- timestamp = xstrprintf ("%ld:%ld %s%s",
- (long) tm.tv_sec, (long) tm.tv_usec,
- linebuffer,
- need_nl ? "\n": "");
- make_cleanup (xfree, timestamp);
- fputs_unfiltered (timestamp, stream);
+ std::string timestamp = string_printf ("%ld.%06ld %s%s",
+ (long) s.count (),
+ (long) us.count (),
+ linebuffer, need_nl ? "\n": "");
+ fputs_unfiltered (timestamp.c_str (), stream);
}
else
fputs_unfiltered (linebuffer, stream);
if (template_string != (char *) NULL && string_to_compare != (char *) NULL
&& strlen (string_to_compare) <= strlen (template_string))
match =
- (strncmp
- (template_string, string_to_compare, strlen (string_to_compare)) == 0);
+ (startswith (template_string, string_to_compare));
else
match = 0;
return match;
}
-static void
-pagination_on_command (char *arg, int from_tty)
-{
- pagination_enabled = 1;
-}
-
-static void
-pagination_off_command (char *arg, int from_tty)
-{
- pagination_enabled = 0;
-}
-
static void
show_debug_timestamp (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
show_lines_per_page,
&setlist, &showlist);
- init_page_info ();
-
add_setshow_boolean_cmd ("pagination", class_support,
&pagination_enabled, _("\
Set state of GDB output pagination."), _("\
show_pagination_enabled,
&setlist, &showlist);
- if (xdb_commands)
- {
- add_com ("am", class_support, pagination_on_command,
- _("Enable pagination"));
- add_com ("sm", class_support, pagination_off_command,
- _("Disable pagination"));
- }
-
add_setshow_boolean_cmd ("sevenbit-strings", class_support,
&sevenbit_strings, _("\
Set printing of 8-bit characters in strings as \\nnn."), _("\
hashval_t
core_addr_hash (const void *ap)
{
- const CORE_ADDR *addrp = ap;
+ const CORE_ADDR *addrp = (const CORE_ADDR *) ap;
return *addrp;
}
int
core_addr_eq (const void *ap, const void *bp)
{
- const CORE_ADDR *addr_ap = ap;
- const CORE_ADDR *addr_bp = bp;
+ const CORE_ADDR *addr_ap = (const CORE_ADDR *) ap;
+ const CORE_ADDR *addr_bp = (const CORE_ADDR *) bp;
return *addr_ap == *addr_bp;
}
char *
gdb_realpath (const char *filename)
{
- /* Method 1: The system has a compile time upper bound on a filename
- path. Use that and realpath() to canonicalize the name. This is
- the most common case. Note that, if there isn't a compile time
- upper bound, you want to avoid realpath() at all costs. */
-#if defined (HAVE_REALPATH) && defined (PATH_MAX)
- {
- char buf[PATH_MAX];
- const char *rp = realpath (filename, buf);
-
- if (rp == NULL)
- rp = filename;
- return xstrdup (rp);
- }
-#endif /* HAVE_REALPATH */
-
- /* Method 2: The host system (i.e., GNU) has the function
- canonicalize_file_name() which malloc's a chunk of memory and
- returns that, use that. */
-#if defined(HAVE_CANONICALIZE_FILE_NAME)
- {
- char *rp = canonicalize_file_name (filename);
-
- if (rp == NULL)
- return xstrdup (filename);
- else
- return rp;
- }
-#endif
-
- /* FIXME: cagney/2002-11-13:
-
- Method 2a: Use realpath() with a NULL buffer. Some systems, due
- to the problems described in method 3, have modified their
- realpath() implementation so that it will allocate a buffer when
- NULL is passed in. Before this can be used, though, some sort of
- configure time test would need to be added. Otherwize the code
- will likely core dump. */
-
- /* Method 3: Now we're getting desperate! The system doesn't have a
- compile time buffer size and no alternative function. Query the
- OS, using pathconf(), for the buffer limit. Care is needed
- though, some systems do not limit PATH_MAX (return -1 for
- pathconf()) making it impossible to pass a correctly sized buffer
- to realpath() (it could always overflow). On those systems, we
- skip this. */
-#if defined (HAVE_REALPATH) && defined (_PC_PATH_MAX) && defined(HAVE_ALLOCA)
- {
- /* Find out the max path size. */
- long path_max = pathconf ("/", _PC_PATH_MAX);
-
- if (path_max > 0)
- {
- /* PATH_MAX is bounded. */
- char *buf = alloca (path_max);
- char *rp = realpath (filename, buf);
-
- return xstrdup (rp ? rp : filename);
- }
- }
-#endif
+/* On most hosts, we rely on canonicalize_file_name to compute
+ the FILENAME's realpath.
+
+ But the situation is slightly more complex on Windows, due to some
+ versions of GCC which were reported to generate paths where
+ backlashes (the directory separator) were doubled. For instance:
+ c:\\some\\double\\slashes\\dir
+ ... instead of ...
+ c:\some\double\slashes\dir
+ Those double-slashes were getting in the way when comparing paths,
+ for instance when trying to insert a breakpoint as follow:
+ (gdb) b c:/some/double/slashes/dir/foo.c:4
+ No source file named c:/some/double/slashes/dir/foo.c:4.
+ (gdb) b c:\some\double\slashes\dir\foo.c:4
+ No source file named c:\some\double\slashes\dir\foo.c:4.
+ To prevent this from happening, we need this function to always
+ strip those extra backslashes. While canonicalize_file_name does
+ perform this simplification, it only works when the path is valid.
+ Since the simplification would be useful even if the path is not
+ valid (one can always set a breakpoint on a file, even if the file
+ does not exist locally), we rely instead on GetFullPathName to
+ perform the canonicalization. */
- /* The MS Windows method. If we don't have realpath, we assume we
- don't have symlinks and just canonicalize to a Windows absolute
- path. GetFullPath converts ../ and ./ in relative paths to
- absolute paths, filling in current drive if one is not given
- or using the current directory of a specified drive (eg, "E:foo").
- It also converts all forward slashes to back slashes. */
- /* The file system is case-insensitive but case-preserving.
- So we do not lowercase the path. Otherwise, we might not
- be able to display the original casing in a given path. */
#if defined (_WIN32)
{
char buf[MAX_PATH];
DWORD len = GetFullPathName (filename, MAX_PATH, buf, NULL);
+ /* The file system is case-insensitive but case-preserving.
+ So it is important we do not lowercase the path. Otherwise,
+ we might not be able to display the original casing in a given
+ path. */
if (len > 0 && len < MAX_PATH)
return xstrdup (buf);
}
+#else
+ {
+ char *rp = canonicalize_file_name (filename);
+
+ if (rp != NULL)
+ return rp;
+ }
#endif
/* This system is a lost cause, just dup the buffer. */
if (base_name == filename)
return xstrdup (filename);
- dir_name = alloca ((size_t) (base_name - filename + 2));
+ dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
/* Allocate enough space to store the dir_name + plus one extra
character sometimes needed under Windows (see below), and
then the closing \000 character. */
return (v & -n);
}
-/* See utils.h. */
-
-LONGEST
-gdb_sign_extend (LONGEST value, int bit)
-{
- gdb_assert (bit >= 1 && bit <= 8 * sizeof (LONGEST));
-
- if (((value >> (bit - 1)) & 1) != 0)
- {
- LONGEST signbit = ((LONGEST) 1) << (bit - 1);
-
- value = (value ^ signbit) - signbit;
- }
-
- return value;
-}
-
/* Allocation function for the libiberty hash table which uses an
obstack. The obstack is passed as DATA. */
void *
hashtab_obstack_allocate (void *data, size_t size, size_t count)
{
- unsigned int total = size * count;
+ size_t total = size * count;
void *ptr = obstack_alloc ((struct obstack *) data, total);
memset (ptr, 0, total);
return;
}
-/* The bit offset of the highest byte in a ULONGEST, for overflow
- checking. */
-
-#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
-
-/* True (non-zero) iff DIGIT is a valid digit in radix BASE,
- where 2 <= BASE <= 36. */
-
-static int
-is_digit_in_base (unsigned char digit, int base)
-{
- if (!isalnum (digit))
- return 0;
- if (base <= 10)
- return (isdigit (digit) && digit < base + '0');
- else
- return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
-}
-
-static int
-digit_to_int (unsigned char c)
-{
- if (isdigit (c))
- return c - '0';
- else
- return tolower (c) - 'a' + 10;
-}
-
-/* As for strtoul, but for ULONGEST results. */
-
-ULONGEST
-strtoulst (const char *num, const char **trailer, int base)
-{
- unsigned int high_part;
- ULONGEST result;
- int minus = 0;
- int i = 0;
-
- /* Skip leading whitespace. */
- while (isspace (num[i]))
- i++;
-
- /* Handle prefixes. */
- if (num[i] == '+')
- i++;
- else if (num[i] == '-')
- {
- minus = 1;
- i++;
- }
-
- if (base == 0 || base == 16)
- {
- if (num[i] == '0' && (num[i + 1] == 'x' || num[i + 1] == 'X'))
- {
- i += 2;
- if (base == 0)
- base = 16;
- }
- }
-
- if (base == 0 && num[i] == '0')
- base = 8;
-
- if (base == 0)
- base = 10;
-
- if (base < 2 || base > 36)
- {
- errno = EINVAL;
- return 0;
- }
-
- result = high_part = 0;
- for (; is_digit_in_base (num[i], base); i += 1)
- {
- result = result * base + digit_to_int (num[i]);
- high_part = high_part * base + (unsigned int) (result >> HIGH_BYTE_POSN);
- result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
- if (high_part > 0xff)
- {
- errno = ERANGE;
- result = ~ (ULONGEST) 0;
- high_part = 0;
- minus = 0;
- break;
- }
- }
-
- if (trailer != NULL)
- *trailer = &num[i];
-
- result = result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
- if (minus)
- return -result;
- else
- return result;
-}
-
/* Simple, portable version of dirname that does not modify its
argument. */
-char *
+std::string
ldirname (const char *filename)
{
+ std::string dirname;
const char *base = lbasename (filename);
- char *dirname;
while (base > filename && IS_DIR_SEPARATOR (base[-1]))
--base;
if (base == filename)
- return NULL;
+ return dirname;
- dirname = xmalloc (base - filename + 2);
- memcpy (dirname, filename, base - filename);
+ dirname = std::string (filename, base - filename);
/* On DOS based file systems, convert "d:foo" to "d:.", so that we
create "d:./bar" later instead of the (different) "d:/bar". */
&& !IS_DIR_SEPARATOR (filename[0]))
dirname[base++ - filename] = '.';
- dirname[base - filename] = '\0';
return dirname;
}
+ strlen (AMBIGUOUS_MESS2);
for (p = matching; *p; p++)
ret_len += strlen (*p) + 1;
- ret = xmalloc (ret_len + 1);
+ ret = (char *) xmalloc (ret_len + 1);
retp = ret;
make_cleanup (xfree, ret);
/* Return ARGS parsed as a valid pid, or throw an error. */
int
-parse_pid_to_attach (char *args)
+parse_pid_to_attach (const char *args)
{
unsigned long pid;
char *dummy;
if (!args)
error_no_arg (_("process-id to attach"));
- dummy = args;
+ dummy = (char *) args;
pid = strtoul (args, &dummy, 0);
/* Some targets don't set errno on errors, grrr! */
if ((pid == 0 && dummy == args) || dummy != &args[strlen (args)])
int
producer_is_gcc_ge_4 (const char *producer)
{
- const char *cs;
int major, minor;
- if (producer == NULL)
- {
- /* For unknown compilers expect their behavior is not compliant. For GCC
- this case can also happen for -gdwarf-4 type units supported since
- gcc-4.5. */
-
- return -1;
- }
+ if (! producer_is_gcc (producer, &major, &minor))
+ return -1;
+ if (major < 4)
+ return -1;
+ if (major > 4)
+ return INT_MAX;
+ return minor;
+}
- /* Skip any identifier after "GNU " - such as "C++" or "Java". */
+/* Returns nonzero if the given PRODUCER string is GCC and sets the MAJOR
+ and MINOR versions when not NULL. Returns zero if the given PRODUCER
+ is NULL or it isn't GCC. */
- if (strncmp (producer, "GNU ", strlen ("GNU ")) != 0)
- {
- /* For non-GCC compilers expect their behavior is not compliant. */
+int
+producer_is_gcc (const char *producer, int *major, int *minor)
+{
+ const char *cs;
- return -1;
- }
- cs = &producer[strlen ("GNU ")];
- while (*cs && !isdigit (*cs))
- cs++;
- if (sscanf (cs, "%d.%d", &major, &minor) != 2)
+ if (producer != NULL && startswith (producer, "GNU "))
{
- /* Not recognized as GCC. */
-
- return -1;
+ int maj, min;
+
+ if (major == NULL)
+ major = &maj;
+ if (minor == NULL)
+ minor = &min;
+
+ /* Skip any identifier after "GNU " - such as "C11" or "C++".
+ A full producer string might look like:
+ "GNU C 4.7.2"
+ "GNU Fortran 4.8.2 20140120 (Red Hat 4.8.2-16) -mtune=generic ..."
+ "GNU C++14 5.0.0 20150123 (experimental)"
+ */
+ cs = &producer[strlen ("GNU ")];
+ while (*cs && !isspace (*cs))
+ cs++;
+ if (*cs && isspace (*cs))
+ cs++;
+ if (sscanf (cs, "%d.%d", major, minor) == 2)
+ return 1;
}
- if (major < 4)
- return -1;
- if (major > 4)
- return INT_MAX;
- return minor;
+ /* Not recognized as GCC. */
+ return 0;
}
/* Helper for make_cleanup_free_char_ptr_vec. */
static void
do_free_char_ptr_vec (void *arg)
{
- VEC (char_ptr) *char_ptr_vec = arg;
+ VEC (char_ptr) *char_ptr_vec = (VEC (char_ptr) *) arg;
free_char_ptr_vec (char_ptr_vec);
}
{
char *string_new;
- string_new = xrealloc (string, (strlen (string) + to_len + 1));
+ string_new
+ = (char *) xrealloc (string, (strlen (string) + to_len + 1));
/* Relocate the current S pointer. */
s = s - string + string_new;
sa.sa_flags = 0;
sigaction (SIGALRM, &sa, &old_sa);
#else
- void (*ofunc) ();
+ sighandler_t ofunc;
- ofunc = (void (*)()) signal (SIGALRM, sigalrm_handler);
+ ofunc = signal (SIGALRM, sigalrm_handler);
#endif
alarm (timeout);
/* Replace '\' by '/' in both strings. */
- pattern_slash = alloca (strlen (pattern) + 1);
+ pattern_slash = (char *) alloca (strlen (pattern) + 1);
strcpy (pattern_slash, pattern);
pattern = pattern_slash;
for (; *pattern_slash != 0; pattern_slash++)
if (IS_DIR_SEPARATOR (*pattern_slash))
*pattern_slash = '/';
- string_slash = alloca (strlen (string) + 1);
+ string_slash = (char *) alloca (strlen (string) + 1);
strcpy (string_slash, string);
string = string_slash;
for (; *string_slash != 0; string_slash++)
return fnmatch (pattern, string, flags);
}
+/* Return the number of path elements in PATH.
+ / = 1
+ /foo = 2
+ /foo/ = 2
+ foo/bar = 2
+ foo/ = 1 */
+
+int
+count_path_elements (const char *path)
+{
+ int count = 0;
+ const char *p = path;
+
+ if (HAS_DRIVE_SPEC (p))
+ {
+ p = STRIP_DRIVE_SPEC (p);
+ ++count;
+ }
+
+ while (*p != '\0')
+ {
+ if (IS_DIR_SEPARATOR (*p))
+ ++count;
+ ++p;
+ }
+
+ /* Backup one if last character is /, unless it's the only one. */
+ if (p > path + 1 && IS_DIR_SEPARATOR (p[-1]))
+ --count;
+
+ /* Add one for the file name, if present. */
+ if (p > path && !IS_DIR_SEPARATOR (p[-1]))
+ ++count;
+
+ return count;
+}
+
+/* Remove N leading path elements from PATH.
+ N must be non-negative.
+ If PATH has more than N path elements then return NULL.
+ If PATH has exactly N path elements then return "".
+ See count_path_elements for a description of how we do the counting. */
+
+const char *
+strip_leading_path_elements (const char *path, int n)
+{
+ int i = 0;
+ const char *p = path;
+
+ gdb_assert (n >= 0);
+
+ if (n == 0)
+ return p;
+
+ if (HAS_DRIVE_SPEC (p))
+ {
+ p = STRIP_DRIVE_SPEC (p);
+ ++i;
+ }
+
+ while (i < n)
+ {
+ while (*p != '\0' && !IS_DIR_SEPARATOR (*p))
+ ++p;
+ if (*p == '\0')
+ {
+ if (i + 1 == n)
+ return "";
+ return NULL;
+ }
+ ++p;
+ ++i;
+ }
+
+ return p;
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_utils;
{
add_internal_problem_command (&internal_error_problem);
add_internal_problem_command (&internal_warning_problem);
+ add_internal_problem_command (&demangler_warning_problem);
}