/* General utility routines for GDB, the GNU debugger.
- Copyright (C) 1986-2016 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 <ctype.h>
#include "gdb_wait.h"
#include "event-top.h"
#endif
#include <signal.h>
-#include "timeval-utils.h"
#include "gdbcmd.h"
#include "serial.h"
#include "bfd.h"
#include "readline/readline.h"
-#include "gdb_sys_time.h"
-#include <time.h>
+#include <chrono>
#include "gdb_usleep.h"
#include "interps.h"
#include "gdb_regex.h"
+#include "job-control.h"
+#include "common/selftest.h"
+#include "common/gdb_optional.h"
#if !HAVE_DECL_MALLOC
extern PTR malloc (); /* ARI: PTR */
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. */
static int debug_timestamp = 0;
-/* Nonzero if we have job control. */
-
-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.) */
/* String to be printed before warning messages, if any. */
-char *warning_pre_print = "\nwarning: ";
+const char *warning_pre_print = "\nwarning: ";
int pagination_enabled = 1;
static void
because while they use the "cleanup API" they are not part of the
"cleanup API". */
-static void
-do_freeargv (void *arg)
-{
- freeargv ((char **) arg);
-}
-
-struct cleanup *
-make_cleanup_freeargv (char **arg)
-{
- 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 ((bfd *) arg);
-}
-
-struct cleanup *
-make_cleanup_bfd_unref (bfd *abfd)
-{
- return make_cleanup (do_bfd_close_cleanup, abfd);
-}
-
-/* Helper function which does the work for make_cleanup_fclose. */
-
-static void
-do_fclose_cleanup (void *arg)
-{
- FILE *file = (FILE *) arg;
-
- fclose (file);
-}
-
-/* Return a new cleanup that closes FILE. */
-
-struct cleanup *
-make_cleanup_fclose (FILE *file)
-{
- return make_cleanup (do_fclose_cleanup, file);
-}
-
-/* Helper function which does the work for make_cleanup_obstack_free. */
-
-static void
-do_obstack_free (void *arg)
-{
- struct obstack *ob = (struct obstack *) arg;
-
- obstack_free (ob, NULL);
-}
-
-/* Return a new cleanup that frees OBSTACK. */
-
-struct cleanup *
-make_cleanup_obstack_free (struct obstack *obstack)
-{
- return make_cleanup (do_obstack_free, obstack);
-}
-
-static void
-do_ui_file_delete (void *arg)
-{
- ui_file_delete ((struct ui_file *) 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 = (struct ui_out *) arg;
-
- if (ui_out_redirect (uiout, NULL) < 0)
- warning (_("Cannot restore redirection of the current output protocol"));
-}
-
-/* Return a new cleanup that pops the last redirection by ui_out_redirect
- with NULL parameter. */
-
-struct cleanup *
-make_cleanup_ui_out_redirect_pop (struct ui_out *uiout)
-{
- return make_cleanup (do_ui_out_redirect_pop, uiout);
-}
-
static void
do_free_section_addr_info (void *arg)
{
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_t) 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_out_closure
-{
- struct ui_out **variable;
- struct ui_out *value;
-};
-
-static void
-do_restore_ui_out (void *p)
-{
- struct restore_ui_out_closure *closure
- = (struct restore_ui_out_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_out (struct ui_out **variable)
-{
- struct restore_ui_out_closure *c = XNEW (struct restore_ui_out_closure);
-
- c->variable = variable;
- c->value = *variable;
-
- return make_cleanup_dtor (do_restore_ui_out, (void *) c, xfree);
-}
-
-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
return make_cleanup (do_value_free, value);
}
-/* Helper for make_cleanup_free_so. */
-
-static void
-do_free_so (void *arg)
-{
- struct so_list *so = (struct so_list *) arg;
-
- free_so (so);
-}
-
-/* Make cleanup handler calling free_so for SO. */
-
-struct cleanup *
-make_cleanup_free_so (struct so_list *so)
-{
- return make_cleanup (do_free_so, so);
-}
-
-/* Helper for make_cleanup_restore_current_language. */
-
-static void
-do_restore_current_language (void *p)
-{
- enum language saved_lang = (enum language) (uintptr_t) p;
-
- set_language (saved_lang);
-}
-
-/* Remember the current value of CURRENT_LANGUAGE and make it restored when
- the cleanup is run. */
-
-struct cleanup *
-make_cleanup_restore_current_language (void)
-{
- enum language saved_lang = current_language->la_language;
-
- return make_cleanup (do_restore_current_language,
- (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
(*deprecated_warning_hook) (string, args);
else
{
- struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
-
+ gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
if (target_supports_terminal_ours ())
{
- make_cleanup_restore_target_terminal ();
- target_terminal_ours_for_output ();
+ term_state.emplace ();
+ target_terminal::ours_for_output ();
}
if (filtered_printing_initialized ())
wrap_here (""); /* Force out any buffered output. */
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)
+error_stream (const string_file &stream)
{
- char *message = ui_file_xstrdup (stream, NULL);
-
- make_cleanup (xfree, message);
- error (("%s"), message);
+ error (("%s"), stream.c_str ());
}
/* Emit a message and abort. */
static void ATTRIBUTE_NORETURN
abort_with_message (const char *msg)
{
- if (gdb_stderr == NULL)
+ if (current_ui == NULL)
fputs (msg, stderr);
else
fputs_unfiltered (msg, gdb_stderr);
}
/* Fall back to abort_with_message if gdb_stderr is not set up. */
- if (gdb_stderr == NULL)
+ if (current_ui == NULL)
{
fputs (reason, stderr);
abort_with_message ("\n");
}
/* Try to get the message out and at the start of a new line. */
+ gdb::optional<target_terminal::scoped_restore_terminal_state> term_state;
if (target_supports_terminal_ours ())
{
- make_cleanup_restore_target_terminal ();
- target_terminal_ours_for_output ();
+ term_state.emplace ();
+ target_terminal::ours_for_output ();
}
if (filtered_printing_initialized ())
begin_line ();
}
/* Return a newly allocated string, containing the PREFIX followed
- by the system error message for errno (separated by a colon).
-
- The result must be deallocated after use. */
+ by the system error message for errno (separated by a colon). */
-static char *
+static std::string
perror_string (const char *prefix)
{
char *err;
- char *combined;
err = safe_strerror (errno);
- combined = (char *) xmalloc (strlen (err) + strlen (prefix) + 3);
- strcpy (combined, prefix);
- strcat (combined, ": ");
- strcat (combined, err);
-
- return combined;
+ return std::string (prefix) + ": " + err;
}
/* Print the system error message for errno, and also mention STRING
void
throw_perror_with_name (enum errors errcode, const char *string)
{
- char *combined;
-
- combined = perror_string (string);
- make_cleanup (xfree, combined);
+ std::string combined = perror_string (string);
/* I understand setting these is a matter of taste. Still, some people
may clear errno but not know about bfd_error. Doing this here is not
bfd_set_error (bfd_error_no_error);
errno = 0;
- throw_error (errcode, _("%s."), combined);
+ throw_error (errcode, _("%s."), combined.c_str ());
}
/* See throw_perror_with_name, ERRCODE defaults here to GENERIC_ERROR. */
void
perror_warning_with_name (const char *string)
{
- char *combined;
-
- combined = perror_string (string);
- warning (_("%s"), combined);
- xfree (combined);
+ std::string combined = perror_string (string);
+ warning (_("%s"), combined.c_str ());
}
/* Print the system error message for ERRCODE, and also mention STRING
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
\f
-/* A cleanup function that calls regfree. */
-
-static void
-do_regfree_cleanup (void *r)
-{
- regfree ((regex_t *) r);
-}
-
-/* Create a new cleanup that frees the compiled regular expression R. */
-
-struct cleanup *
-make_regfree_cleanup (regex_t *r)
-{
- return make_cleanup (do_regfree_cleanup, r);
-}
-
-/* Return an xmalloc'd error message resulting from a regular
- expression compilation failure. */
+/* An RAII class that sets up to handle input and then tears down
+ during destruction. */
-char *
-get_regcomp_error (int code, regex_t *rx)
+class scoped_input_handler
{
- size_t length = regerror (code, rx, NULL, 0);
- char *result = (char *) xmalloc (length);
+public:
- regerror (code, rx, result, length);
- return result;
-}
+ scoped_input_handler ()
+ : m_quit_handler (make_scoped_restore (&quit_handler,
+ default_quit_handler)),
+ m_ui (NULL)
+ {
+ target_terminal::ours ();
+ ui_register_input_event_handler (current_ui);
+ if (current_ui->prompt_state == PROMPT_BLOCKED)
+ m_ui = current_ui;
+ }
-/* Compile a regexp and throw an exception on error. This returns a
- cleanup to free the resulting pattern on success. RX must not be
- NULL. */
+ ~scoped_input_handler ()
+ {
+ if (m_ui != NULL)
+ ui_unregister_input_event_handler (m_ui);
+ }
-struct cleanup *
-compile_rx_or_error (regex_t *pattern, const char *rx, const char *message)
-{
- int code;
+ DISABLE_COPY_AND_ASSIGN (scoped_input_handler);
- gdb_assert (rx != NULL);
+private:
- code = regcomp (pattern, rx, REG_NOSUB);
- if (code != 0)
- {
- char *err = get_regcomp_error (code, pattern);
+ /* Save and restore the terminal state. */
+ target_terminal::scoped_restore_terminal_state m_term_state;
- make_cleanup (xfree, err);
- error (("%s: %s"), message, err);
- }
+ /* Save and restore the quit handler. */
+ scoped_restore m_quit_handler;
- return make_regfree_cleanup (pattern);
-}
+ /* The saved UI, if non-NULL. */
+ struct ui *m_ui;
+};
\f
int retval;
int def_value;
char def_answer, not_def_answer;
- char *y_string, *n_string, *question, *prompt;
- /* Used to add duration we waited for user to respond to
- prompt_for_continue_wait_time. */
- struct timeval prompt_started, prompt_ended, prompt_delta;
+ const char *y_string, *n_string;
+ char *question, *prompt;
struct cleanup *old_chain;
/* Set up according to which answer is the default. */
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)
{
+ target_terminal::scoped_restore_terminal_state term_state;
+ target_terminal::ours_for_output ();
wrap_here ("");
vfprintf_filtered (gdb_stdout, ctlstr, args);
if (deprecated_query_hook)
{
+ target_terminal::scoped_restore_terminal_state term_state;
return deprecated_query_hook (ctlstr, args);
}
- old_chain = make_cleanup (null_cleanup, NULL);
-
/* Format the question outside of the loop, to avoid reusing args. */
question = xstrvprintf (ctlstr, args);
- make_cleanup (xfree, question);
+ 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 for calculating time spend waiting for user. */
- gettimeofday (&prompt_started, NULL);
+ /* 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 ();
+
+ scoped_input_handler prepare_input;
while (1)
{
}
/* 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_filtered (("\n\032\032post-query\n"));
static int
host_char_to_target (struct gdbarch *gdbarch, int c, int *target_c)
{
- struct obstack host_data;
char the_char = c;
- struct cleanup *cleanups;
int result = 0;
- obstack_init (&host_data);
- cleanups = make_cleanup_obstack_free (&host_data);
+ auto_obstack host_data;
convert_between_encodings (target_charset (gdbarch), host_charset (),
(gdb_byte *) &the_char, 1, 1,
*target_c = *(char *) obstack_base (&host_data);
}
- do_cleanups (cleanups);
return result;
}
/* 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)
/* Readline should have fetched the termcap entry for us.
Only try to use tgetnum function if rl_get_screen_size
did not return a useful value. */
- if (((rows <= 0) && (tgetnum ("li") < 0))
+ if (((rows <= 0) && (tgetnum ((char *) "li") < 0))
/* Also disable paging if inside Emacs. $EMACS was used
before Emacs v25.1, $INSIDE_EMACS is used since then. */
|| getenv ("EMACS") || getenv ("INSIDE_EMACS"))
{
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;
- struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
-
- 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"));
beyond the end of the screen. */
reinitialize_more_filter ();
- /* We'll need to handle input. */
- target_terminal_ours ();
+ scoped_input_handler prepare_input;
/* Call gdb_readline_wrapper, not readline, in order to keep an
event loop running. */
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"));
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)
|| 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;
/* Print prefix and suffix after each line. */
static int new_line = 1;
static int return_p = 0;
- static char *prev_prefix = "";
- static char *prev_suffix = "";
+ static const char *prev_prefix = "";
+ static const char *prev_suffix = "";
if (*string == '\n')
return_p = 0;
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);
}
}
-/* Do a strcmp() type operation on STRING1 and STRING2, ignoring any
- differences in whitespace. Returns 0 if they match, non-zero if they
- don't (slightly different than strcmp()'s range of return values).
+/* Modes of operation for strncmp_iw_with_mode. */
- As an extra hack, string1=="FOO(ARGS)" matches string2=="FOO".
- This "feature" is useful when searching for matching C++ function names
- (such as if the user types 'break FOO', where FOO is a mangled C++
- function). */
+enum class strncmp_iw_mode
+{
+ /* Work like strncmp, while ignoring whitespace. */
+ NORMAL,
-int
-strcmp_iw (const char *string1, const char *string2)
+ /* Like NORMAL, but also apply the strcmp_iw hack. I.e.,
+ string1=="FOO(PARAMS)" matches string2=="FOO". */
+ MATCH_PARAMS,
+};
+
+/* Helper for strncmp_iw and strcmp_iw. */
+
+static int
+strncmp_iw_with_mode (const char *string1, const char *string2,
+ size_t string2_len, strncmp_iw_mode mode)
{
- while ((*string1 != '\0') && (*string2 != '\0'))
+ const char *end_str2 = string2 + string2_len;
+
+ while (1)
{
while (isspace (*string1))
- {
- string1++;
- }
- while (isspace (*string2))
- {
- string2++;
- }
+ string1++;
+ while (string2 < end_str2 && isspace (*string2))
+ string2++;
+ if (*string1 == '\0' || string2 == end_str2)
+ break;
if (case_sensitivity == case_sensitive_on && *string1 != *string2)
break;
if (case_sensitivity == case_sensitive_off
&& (tolower ((unsigned char) *string1)
!= tolower ((unsigned char) *string2)))
break;
- if (*string1 != '\0')
- {
- string1++;
- string2++;
- }
+
+ string1++;
+ string2++;
}
- return (*string1 != '\0' && *string1 != '(') || (*string2 != '\0');
+
+ if (string2 == end_str2)
+ {
+ if (mode == strncmp_iw_mode::NORMAL)
+ return 0;
+ else
+ return (*string1 != '\0' && *string1 != '(');
+ }
+ else
+ return 1;
+}
+
+/* See utils.h. */
+
+int
+strncmp_iw (const char *string1, const char *string2, size_t string2_len)
+{
+ return strncmp_iw_with_mode (string1, string2, string2_len,
+ strncmp_iw_mode::NORMAL);
+}
+
+/* See utils.h. */
+
+int
+strcmp_iw (const char *string1, const char *string2)
+{
+ return strncmp_iw_with_mode (string1, string2, strlen (string2),
+ strncmp_iw_mode::MATCH_PARAMS);
}
/* This is like strcmp except that it ignores whitespace and treats
** at index 0.
*/
int
-subset_compare (char *string_to_compare, char *template_string)
+subset_compare (const char *string_to_compare, const char *template_string)
{
int match;
return addr;
}
-char *
+gdb::unique_xmalloc_ptr<char>
gdb_realpath (const char *filename)
{
/* On most hosts, we rely on canonicalize_file_name to compute
we might not be able to display the original casing in a given
path. */
if (len > 0 && len < MAX_PATH)
- return xstrdup (buf);
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (buf));
}
#else
{
char *rp = canonicalize_file_name (filename);
if (rp != NULL)
- return rp;
+ return gdb::unique_xmalloc_ptr<char> (rp);
}
#endif
/* This system is a lost cause, just dup the buffer. */
- return xstrdup (filename);
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (filename));
+}
+
+#if GDB_SELF_TEST
+
+static void
+gdb_realpath_check_trailer (const char *input, const char *trailer)
+{
+ gdb::unique_xmalloc_ptr<char> result = gdb_realpath (input);
+
+ size_t len = strlen (result.get ());
+ size_t trail_len = strlen (trailer);
+
+ SELF_CHECK (len >= trail_len
+ && strcmp (result.get () + len - trail_len, trailer) == 0);
}
+static void
+gdb_realpath_tests ()
+{
+ /* A file which contains a directory prefix. */
+ gdb_realpath_check_trailer ("./xfullpath.exp", "/xfullpath.exp");
+ /* A file which contains a directory prefix. */
+ gdb_realpath_check_trailer ("../../defs.h", "/defs.h");
+ /* A one-character filename. */
+ gdb_realpath_check_trailer ("./a", "/a");
+ /* A file in the root directory. */
+ gdb_realpath_check_trailer ("/root_file_which_should_exist",
+ "/root_file_which_should_exist");
+ /* A file which does not have a directory prefix. */
+ gdb_realpath_check_trailer ("xfullpath.exp", "xfullpath.exp");
+ /* A one-char filename without any directory prefix. */
+ gdb_realpath_check_trailer ("a", "a");
+ /* An empty filename. */
+ gdb_realpath_check_trailer ("", "");
+}
+
+#endif /* GDB_SELF_TEST */
+
/* Return a copy of FILENAME, with its directory prefix canonicalized
by gdb_realpath. */
-char *
+gdb::unique_xmalloc_ptr<char>
gdb_realpath_keepfile (const char *filename)
{
const char *base_name = lbasename (filename);
char *dir_name;
- char *real_path;
char *result;
/* Extract the basename of filename, and return immediately
a copy of filename if it does not contain any directory prefix. */
if (base_name == filename)
- return xstrdup (filename);
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (filename));
dir_name = (char *) alloca ((size_t) (base_name - filename + 2));
/* Allocate enough space to store the dir_name + plus one extra
/* Canonicalize the directory prefix, and build the resulting
filename. If the dirname realpath already contains an ending
directory separator, avoid doubling it. */
- real_path = gdb_realpath (dir_name);
+ gdb::unique_xmalloc_ptr<char> path_storage = gdb_realpath (dir_name);
+ const char *real_path = path_storage.get ();
if (IS_DIR_SEPARATOR (real_path[strlen (real_path) - 1]))
result = concat (real_path, base_name, (char *) NULL);
else
result = concat (real_path, SLASH_STRING, base_name, (char *) NULL);
- xfree (real_path);
- return result;
+ return gdb::unique_xmalloc_ptr<char> (result);
}
/* Return PATH in absolute form, performing tilde-expansion if necessary.
PATH cannot be NULL or the empty string.
- This does not resolve symlinks however, use gdb_realpath for that.
- Space for the result is allocated with malloc.
- If the path is already absolute, it is strdup'd.
- If there is a problem computing the absolute path, the path is returned
- unchanged (still strdup'd). */
+ This does not resolve symlinks however, use gdb_realpath for that. */
-char *
+gdb::unique_xmalloc_ptr<char>
gdb_abspath (const char *path)
{
gdb_assert (path != NULL && path[0] != '\0');
if (path[0] == '~')
- return tilde_expand (path);
+ return gdb::unique_xmalloc_ptr<char> (tilde_expand (path));
if (IS_ABSOLUTE_PATH (path))
- return xstrdup (path);
+ return gdb::unique_xmalloc_ptr<char> (xstrdup (path));
/* Beware the // my son, the Emacs barfs, the botch that catch... */
- return concat (current_directory,
- IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1])
- ? "" : SLASH_STRING,
- path, (char *) NULL);
+ return gdb::unique_xmalloc_ptr<char>
+ (concat (current_directory,
+ IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1])
+ ? "" : SLASH_STRING,
+ path, (char *) NULL));
}
ULONGEST
/* 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 = (char *) 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;
}
-/* Call libiberty's buildargv, and return the result.
- If buildargv fails due to out-of-memory, call nomem.
- Therefore, the returned value is guaranteed to be non-NULL,
- unless the parameter itself is NULL. */
+/* See utils.h. */
-char **
-gdb_buildargv (const char *s)
+void
+gdb_argv::reset (const char *s)
{
char **argv = buildargv (s);
if (s != NULL && argv == NULL)
malloc_failure (0);
- return argv;
+
+ freeargv (m_argv);
+ m_argv = argv;
}
int
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 ..."
return p;
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_utils;
-
void
_initialize_utils (void)
{
add_internal_problem_command (&internal_error_problem);
add_internal_problem_command (&internal_warning_problem);
add_internal_problem_command (&demangler_warning_problem);
+
+#if GDB_SELF_TEST
+ selftests::register_test ("gdb_realpath", gdb_realpath_tests);
+#endif
}