/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986-2015 Free Software Foundation, Inc.
+ Copyright (C) 1986-2016 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 <ctype.h>
#include "gdb_wait.h"
#include "event-top.h"
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)
{
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
- = (struct restore_ui_file_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
(*deprecated_warning_hook) (string, args);
else
{
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+
if (target_supports_terminal_ours ())
- target_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);
fputs_unfiltered (warning_pre_print, gdb_stderr);
vfprintf_unfiltered (gdb_stderr, string, args);
fprintf_unfiltered (gdb_stderr, "\n");
+
+ do_cleanups (old_chain);
}
}
void
error_stream (struct ui_file *stream)
{
- char *message = ui_file_xstrdup (stream, NULL);
+ std::string message = ui_file_as_string (stream);
- make_cleanup (xfree, message);
- error (("%s"), message);
+ error (("%s"), message.c_str ());
}
/* Emit a message and abort. */
/* Try to get the message out and at the start of a new line. */
if (target_supports_terminal_ours ())
- target_terminal_ours ();
+ {
+ make_cleanup_restore_target_terminal ();
+ target_terminal_ours_for_output ();
+ }
if (filtered_printing_initialized ())
begin_line ();
void
quit (void)
{
+ struct ui *ui = current_ui;
+
if (sync_quit_force_run)
{
sync_quit_force_run = 0;
- quit_force (NULL, stdin == instream);
+ quit_force (NULL, 0);
}
#ifdef __MSDOS__
void
maybe_quit (void)
{
- if (check_quit_flag () || sync_quit_force_run)
+ if (sync_quit_force_run)
quit ();
+
+ quit_handler ();
+
if (deprecated_interactive_hook)
deprecated_interactive_hook ();
- target_check_pending_interrupt ();
}
\f
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.
/* Used to add duration we waited for user to respond to
prompt_for_continue_wait_time. */
struct timeval prompt_started, prompt_ended, prompt_delta;
+ 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))
{
+ 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" : "");
- xfree (question);
+ make_cleanup (xfree, prompt);
/* Used for calculating time spend waiting for user. */
gettimeofday (&prompt_started, NULL);
+ prepare_to_handle_input ();
+
while (1)
{
char *response, answer;
timeval_add (&prompt_for_continue_wait_time,
&prompt_for_continue_wait_time, &prompt_delta);
- xfree (prompt);
if (annotation_level > 1)
printf_filtered (("\n\032\032post-query\n"));
+ do_cleanups (old_chain);
return retval;
}
\f
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
}
/* 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)
/* Used to add duration we waited for user to respond to
prompt_for_continue_wait_time. */
struct timeval prompt_started, prompt_ended, prompt_delta;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
gettimeofday (&prompt_started, NULL);
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;
+ prepare_to_handle_input ();
- /* We'll need to handle input. */
- target_terminal_ours ();
-
- /* 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. */
+ /* 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);
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)
if (minor == NULL)
minor = &min;
- /* Skip any identifier after "GNU " - such as "C11" "C++" or "Java".
+ /* 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 ..."
/* 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;