otherwise. */
static std::string
-relocate_gdbinit_path_maybe_in_datadir (const std::string &file,
- bool relocatable)
+relocate_file_path_maybe_in_datadir (const std::string &file,
+ bool relocatable)
{
size_t datadir_len = strlen (GDB_DATADIR);
return relocated_path;
}
-/* Compute the locations of init files that GDB should source and
- return them in SYSTEM_GDBINIT, HOME_GDBINIT, LOCAL_GDBINIT. If
- there is no system gdbinit (resp. home gdbinit and local gdbinit)
- to be loaded, then SYSTEM_GDBINIT (resp. HOME_GDBINIT and
- LOCAL_GDBINIT) is set to the empty string. */
-static void
-get_init_files (std::vector<std::string> *system_gdbinit,
- std::string *home_gdbinit,
- std::string *local_gdbinit)
+/* A class to wrap up the logic for finding the three different types of
+ initialisation files GDB uses, system wide, home directory, and current
+ working directory. */
+
+class gdb_initfile_finder
{
- static std::vector<std::string> sysgdbinit;
- static std::string homeinit;
- static std::string localinit;
- static int initialized = 0;
+public:
+ /* Constructor. Finds initialisation files named FILENAME in the home
+ directory or local (current working) directory. System initialisation
+ files are found in both SYSTEM_FILENAME and SYSTEM_DIRNAME if these
+ are not nullptr (either or both can be). The matching *_RELOCATABLE
+ flag is passed through to RELOCATE_FILE_PATH_MAYBE_IN_DATADIR.
+
+ If FILENAME starts with a '.' then when looking in the home directory
+ this first '.' can be ignored in some cases. */
+ explicit gdb_initfile_finder (const char *filename,
+ const char *system_filename,
+ bool system_filename_relocatable,
+ const char *system_dirname,
+ bool system_dirname_relocatable,
+ bool lookup_local_file)
+ {
+ struct stat s;
- if (!initialized)
- {
- struct stat homebuf, cwdbuf, s;
+ if (system_filename != nullptr && system_filename[0] != '\0')
+ {
+ std::string relocated_filename
+ = relocate_file_path_maybe_in_datadir (system_filename,
+ system_filename_relocatable);
+ if (!relocated_filename.empty ()
+ && stat (relocated_filename.c_str (), &s) == 0)
+ m_system_files.push_back (relocated_filename);
+ }
- if (SYSTEM_GDBINIT[0])
- {
- std::string relocated_sysgdbinit
- = relocate_gdbinit_path_maybe_in_datadir
- (SYSTEM_GDBINIT, SYSTEM_GDBINIT_RELOCATABLE);
- if (!relocated_sysgdbinit.empty ()
- && stat (relocated_sysgdbinit.c_str (), &s) == 0)
- sysgdbinit.push_back (relocated_sysgdbinit);
- }
- if (SYSTEM_GDBINIT_DIR[0])
- {
- std::string relocated_gdbinit_dir
- = relocate_gdbinit_path_maybe_in_datadir
- (SYSTEM_GDBINIT_DIR, SYSTEM_GDBINIT_DIR_RELOCATABLE);
- if (!relocated_gdbinit_dir.empty ()) {
- gdb_dir_up dir (opendir (relocated_gdbinit_dir.c_str ()));
+ if (system_dirname != nullptr && system_dirname[0] != '\0')
+ {
+ std::string relocated_dirname
+ = relocate_file_path_maybe_in_datadir (system_dirname,
+ system_dirname_relocatable);
+ if (!relocated_dirname.empty ())
+ {
+ gdb_dir_up dir (opendir (relocated_dirname.c_str ()));
if (dir != nullptr)
{
std::vector<std::string> files;
- for (;;)
+ while (true)
{
struct dirent *ent = readdir (dir.get ());
if (ent == nullptr)
std::string name (ent->d_name);
if (name == "." || name == "..")
continue;
- /* ent->d_type is not available on all systems (e.g. mingw,
- Solaris), so we have to call stat(). */
- std::string filename
- = relocated_gdbinit_dir + SLASH_STRING + name;
- if (stat (filename.c_str (), &s) != 0
+ /* ent->d_type is not available on all systems
+ (e.g. mingw, Solaris), so we have to call stat(). */
+ std::string tmp_filename
+ = relocated_dirname + SLASH_STRING + name;
+ if (stat (tmp_filename.c_str (), &s) != 0
|| !S_ISREG (s.st_mode))
continue;
const struct extension_language_defn *extlang
- = get_ext_lang_of_file (filename.c_str ());
+ = get_ext_lang_of_file (tmp_filename.c_str ());
/* We effectively don't support "set script-extension
- off/soft", because we are loading system init files here,
- so it does not really make sense to depend on a
- setting. */
+ off/soft", because we are loading system init files
+ here, so it does not really make sense to depend on
+ a setting. */
if (extlang != nullptr && ext_lang_present_p (extlang))
- files.push_back (std::move (filename));
+ files.push_back (std::move (tmp_filename));
}
std::sort (files.begin (), files.end ());
- sysgdbinit.insert (sysgdbinit.end (),
- files.begin (), files.end ());
+ m_system_files.insert (m_system_files.end (),
+ files.begin (), files.end ());
}
}
- }
+ }
/* If the .gdbinit file in the current directory is the same as
the $HOME/.gdbinit file, it should not be sourced. homebuf
are zero in case one of them fails (this guarantees that they
won't match if either exists). */
- memset (&homebuf, 0, sizeof (struct stat));
- memset (&cwdbuf, 0, sizeof (struct stat));
+ struct stat homebuf, cwdbuf;
+ memset (&homebuf, 0, sizeof (struct stat));
+ memset (&cwdbuf, 0, sizeof (struct stat));
- homeinit = find_gdb_home_config_file (GDBINIT, &homebuf);
+ m_home_file = find_gdb_home_config_file (filename, &homebuf);
- if (stat (GDBINIT, &cwdbuf) == 0)
- {
- if (homeinit.empty ()
- || memcmp ((char *) &homebuf, (char *) &cwdbuf,
- sizeof (struct stat)))
- localinit = GDBINIT;
- }
+ if (lookup_local_file && stat (filename, &cwdbuf) == 0)
+ {
+ if (m_home_file.empty ()
+ || memcmp ((char *) &homebuf, (char *) &cwdbuf,
+ sizeof (struct stat)))
+ m_local_file = filename;
+ }
+ }
- initialized = 1;
- }
+ DISABLE_COPY_AND_ASSIGN (gdb_initfile_finder);
+
+ /* Return a list of system initialisation files. The list could be
+ empty. */
+ const std::vector<std::string> &system_files () const
+ { return m_system_files; }
+
+ /* Return the path to the home initialisation file. The string can be
+ empty if there is no such file. */
+ const std::string &home_file () const
+ { return m_home_file; }
+
+ /* Return the path to the local initialisation file. The string can be
+ empty if there is no such file. */
+ const std::string &local_file () const
+ { return m_local_file; }
+
+private:
+
+ /* Vector of all system init files in the order they should be processed.
+ Could be empty. */
+ std::vector<std::string> m_system_files;
+
+ /* Initialization file from the home directory. Could be the empty
+ string if there is no such file found. */
+ std::string m_home_file;
- *system_gdbinit = sysgdbinit;
- *home_gdbinit = homeinit;
- *local_gdbinit = localinit;
+ /* Initialization file from the current working directory. Could be the
+ empty string if there is no such file found. */
+ std::string m_local_file;
+};
+
+/* Compute the locations of init files that GDB should source and return
+ them in SYSTEM_GDBINIT, HOME_GDBINIT, LOCAL_GDBINIT. The SYSTEM_GDBINIT
+ can be returned as an empty vector, and HOME_GDBINIT and LOCAL_GDBINIT
+ can be returned as empty strings if there is no init file of that
+ type. */
+
+static void
+get_init_files (std::vector<std::string> *system_gdbinit,
+ std::string *home_gdbinit,
+ std::string *local_gdbinit)
+{
+ /* Cache the file lookup object so we only actually search for the files
+ once. */
+ static gdb::optional<gdb_initfile_finder> init_files;
+ if (!init_files.has_value ())
+ init_files.emplace (GDBINIT, SYSTEM_GDBINIT, SYSTEM_GDBINIT_RELOCATABLE,
+ SYSTEM_GDBINIT_DIR, SYSTEM_GDBINIT_DIR_RELOCATABLE,
+ true);
+
+ *system_gdbinit = init_files->system_files ();
+ *home_gdbinit = init_files->home_file ();
+ *local_gdbinit = init_files->local_file ();
}
/* Start up the event loop. This is the entry point to the event loop
fprintf_unfiltered (stream, _("\
* local init file (see also 'set auto-load local-gdbinit'): ./%s\n\
"), local_gdbinit.c_str ());
+ if (system_gdbinit.empty () && home_gdbinit.empty ()
+ && local_gdbinit.empty ())
+ fprintf_unfiltered (stream, _("\
+ None found.\n"));
fputs_unfiltered (_("\n\
For more information, type \"help\" from within GDB, or consult the\n\
GDB manual (available as on-line info or a printed manual).\n\