From a844f8e10213c19b6e48d6ff98e97bc9f026a42a Mon Sep 17 00:00:00 2001 From: dshaligram Date: Mon, 26 May 2008 15:30:07 +0000 Subject: Better support for settings files that include other files: - Files can be included as "include foo" in .crawlrc instead of using the Lua call: : crawl.read_options('foo'). include foo and the Lua crawl.read_options('foo') are not equivalent - Lua only runs after the start of a new game, which is too late for some option settings. - Crawl searches for included files in this sequence: - Absolute paths: use the path directly (but not if DATA_DIR_PATH is set, since we don't want Crawl to read arbitrary files on multiuser systems). - Search relative to the including file. - Search relative to any -rcdir(s) provided. - Search in the data file search path. - The data file search path now includes settings/ for when we move rc stuff to settings/ .gitignore: ignore saves and morgue dirs correctly. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5256 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/init.txt | 13 +-- crawl-ref/source/acr.cc | 5 +- crawl-ref/source/clua.cc | 13 +-- crawl-ref/source/externs.h | 18 +++ crawl-ref/source/files.cc | 108 ++++++++++++++++-- crawl-ref/source/files.h | 12 ++ crawl-ref/source/initfile.cc | 255 +++++++++++++++++++++++++++++++++++++++---- crawl-ref/source/initfile.h | 7 ++ crawl-ref/source/itemname.cc | 4 + crawl-ref/source/mapmark.cc | 1 + crawl-ref/source/newgame.cc | 28 ++++- 11 files changed, 405 insertions(+), 59 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/init.txt b/crawl-ref/init.txt index 1e31156b5c..1d54405d03 100644 --- a/crawl-ref/init.txt +++ b/crawl-ref/init.txt @@ -8,7 +8,7 @@ # targeting interface. # (New players should just ignore these lines.) # -# : crawl.read_options('docs/034_monster_glyphs.txt') +# include docs/034_monster_glyphs.txt # additional_macro_file = docs/034_command_keys.txt # classic_item_colours = true # classic_hud = true @@ -180,9 +180,11 @@ runrest_ignore_monster = butterfly:1 trapwalk_safe_hp = dart:20,needle:15,arrow:35,bolt:45,spear:40,axe:45,blade:95 -# You can use the travel_stop_message for making autotravel better behaved. -# The following file contains a list of such options, with explanations. -: crawl.read_options('docs/travel_stoppers.txt') +# You can use travel_stop_message to make autotravel stop for situations that +# warrant your attention. This file (travel_stoppers.txt) contains a list of +# travel_stop_message settings, with brief descriptions of what they do. + +include docs/travel_stoppers.txt ##### 4-h Stashes ############################### # @@ -351,9 +353,6 @@ tile_show_items = !?/%=([)X}+\_. # colour.lightgray = black # colour.lightcyan = cyan # colour.yellow = brown -# -# Set the monster glyphs back to the way they were in 0.3.4 -# : crawl.read_options('docs/monster_glyphs.txt') # See options_guide.txt for the options # cset_ascii, cset_ibm, cset_dec, cset_unicode, cset_any, diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 397abc48dd..0f96a4f61e 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -155,7 +155,7 @@ game_state crawl_state; -std::string init_file_location; // externed in newgame.cc +std::string init_file_error; // externed in newgame.cc char info[ INFO_SIZE ]; // messaging queue extern'd everywhere {dlb} @@ -225,7 +225,7 @@ int main( int argc, char *argv[] ) init_monsters(mcolour); // Read the init file. - init_file_location = read_init_file(); + init_file_error = read_init_file(); // now parse the args again, looking for everything else. parse_args( argc, argv, false ); @@ -294,6 +294,7 @@ static void _show_commandline_options_help() puts(" -plain don't use IBM extended characters"); puts(" -dir crawl directory"); puts(" -rc init file name"); + puts(" -rcdir directory that contains (included) rc files"); puts(" -morgue directory to save character dumps"); puts(" -macro directory to save/find macro.txt"); puts(""); diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index 1b80f2f498..982c208388 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -1794,18 +1794,7 @@ static int crawl_read_options(lua_State *ls) return (0); const char* filename = lua_tostring(ls, 1); - FILE* f = fopen( filename, "r" ); - if (f) - { - FileLineInput fl(f); - Options.read_options(fl, true); - fclose(f); - } - else - { - mprf(MSGCH_WARN, "Warning: could not read options file '%s'", filename); - } - + Options.include(filename, true, true); return (0); } diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index b6e6e2bf18..340acef5df 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -1561,7 +1561,23 @@ public: void read_options(InitLineInput &, bool runscripts, bool clear_aliases = true); + void include(const std::string &file, bool resolve, bool runscript); + void report_error(const std::string &error); + + std::string resolve_include(const std::string &file, + const char *type = ""); + + bool was_included(const std::string &file) const; + + static std::string resolve_include( + std::string including_file, + std::string included_file, + const std::vector *rcdirs = NULL) + throw (std::string); + public: + std::string filename; // The name of the file containing options. + // View options std::vector feature_overrides; std::vector mon_glyph_overrides; @@ -1872,6 +1888,7 @@ public: private: std::map aliases; + std::set included; // Files we've included already. public: // Convenience accessors for the second-class options in named_options. @@ -1922,6 +1939,7 @@ private: void add_mon_glyph_override(const std::string &); mon_display parse_mon_glyph(const std::string &s) const; void set_option_fragment(const std::string &s); + bool include_file_directive(const std::string &line, bool runscript); static const std::string interrupt_prefix; }; diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index fe2a654037..02ddf79278 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -281,6 +281,44 @@ std::string get_base_filename(const std::string &filename) return (filename); } +bool is_absolute_path(const std::string &path) +{ + return (!path.empty() + && (path[0] == FILE_SEPARATOR +#if defined(WIN32CONSOLE) || defined(WIN32TILES) + || path.find(':') != std::string::npos +#endif + )); +} + +// Concatenates two paths, separating them with FILE_SEPARATOR if necessary. +// Assumes that the second path is not absolute. +// +// If the first path is empty, returns the second unchanged. The second path +// may be absolute in this case. +std::string catpath(const std::string &first, const std::string &second) +{ + if (first.empty()) + return (second); + + std::string directory = first; + if (directory[directory.length() - 1] != FILE_SEPARATOR) + directory += FILE_SEPARATOR; + directory += second; + + return (directory); +} + +// Given a relative path and a reference file name, returns the relative path +// suffixed to the directory containing the reference file name. Assumes that +// the second path is not absolute. +std::string get_path_relative_to(const std::string &referencefile, + const std::string &relativepath) +{ + return catpath(get_parent_directory(referencefile), + relativepath); +} + std::string change_file_extension(const std::string &filename, const std::string &ext) { @@ -312,7 +350,7 @@ void check_newer(const std::string &target, action(); } -static bool file_exists(const std::string &name) +bool file_exists(const std::string &name) { #ifdef HAVE_STAT struct stat st; @@ -328,12 +366,16 @@ static bool file_exists(const std::string &name) } // Low-tech existence check. -static bool dir_exists(const std::string &dir) +bool dir_exists(const std::string &dir) { #ifdef _MSC_VER DWORD lAttr = GetFileAttributes(dir.c_str()); return (lAttr != INVALID_FILE_ATTRIBUTES && (lAttr & FILE_ATTRIBUTE_DIRECTORY)); +#elif defined(HAVE_STAT) + struct stat st; + const int err = ::stat(dir.c_str(), &st); + return (!err && S_ISDIR(st.st_mode)); #else DIR *d = opendir(dir.c_str()); const bool exists = !!d; @@ -385,36 +427,84 @@ static bool create_dirs(const std::string &dir) return (true); } +// Checks whether the given path is safe to read from. A path is safe if: +// 1. If Unix: It contains no shell metacharacters. +// 2. If DATA_DIR_PATH is set: the path is not an absolute path. +// 3. If DATA_DIR_PATH is set: the path contains no ".." sequence. +void assert_read_safe_path(const std::string &path) throw (std::string) +{ + // Check for rank tomfoolery first: + if (path.empty()) + throw "Empty file name."; + +#ifdef UNIX + if (!shell_safe(path.c_str())) + throw make_stringf("\"%s\" contains bad characters.", + path.c_str()); +#endif + +#ifdef DATA_DIR_PATH + if (is_absolute_path(path)) + throw make_stringf("\"%s\" is an absolute path.", path.c_str()); + + if (path.find("..") != std::string::npos) + throw make_stringf("\"%s\" contains \"..\" sequences.", + path.c_str()); +#endif + + // Path is okay. +} + +bool is_read_safe_path(const std::string &path) +{ + try + { + assert_read_safe_path(path); + } + catch (const std::string &err) + { + return (false); + } + return (true); +} + +std::string canonicalise_file_separator(const std::string &path) +{ +#if FILE_SEPARATOR != '/' + return (replace_all_of(path, "/", std::string(1, FILE_SEPARATOR))); +#else + // No action needed here. + return (path); +#endif +} + std::string datafile_path(std::string basename, bool croak_on_fail, bool test_base_path) { -#if FILE_SEPARATOR != '/' - basename = replace_all_of(basename, "/", std::string(1, FILE_SEPARATOR)); -#endif + basename = canonicalise_file_separator(basename); if (test_base_path && file_exists(basename)) return (basename); - std::string cdir = !SysEnv.crawl_dir.empty()? SysEnv.crawl_dir : ""; - const std::string rawbases[] = { #ifdef DATA_DIR_PATH DATA_DIR_PATH, #else - cdir, + !SysEnv.crawl_dir.empty()? SysEnv.crawl_dir : "", #endif }; const std::string prefixes[] = { std::string("dat") + FILE_SEPARATOR, std::string("docs") + FILE_SEPARATOR, + std::string("settings") + FILE_SEPARATOR, #ifndef DATA_DIR_PATH std::string("..") + FILE_SEPARATOR + "docs" + FILE_SEPARATOR, std::string("..") + FILE_SEPARATOR + "dat" + FILE_SEPARATOR, + std::string("..") + FILE_SEPARATOR + "settings" + FILE_SEPARATOR, std::string("..") + FILE_SEPARATOR, #endif - std::string(".") + FILE_SEPARATOR, "", }; diff --git a/crawl-ref/source/files.h b/crawl-ref/source/files.h index 830f99bc41..3e28c65a30 100644 --- a/crawl-ref/source/files.h +++ b/crawl-ref/source/files.h @@ -34,11 +34,23 @@ enum load_mode_type // referenced in files - newgame - ouch: extern FixedArray tmp_file_pairs; +bool file_exists(const std::string &name); +bool dir_exists(const std::string &dir); +bool is_absolute_path(const std::string &path); +bool is_read_safe_path(const std::string &path); +void assert_read_safe_path(const std::string &path) throw (std::string); + std::string datafile_path(std::string basename, bool croak_on_fail = true, bool test_base_path = false); + std::string get_parent_directory(const std::string &filename); std::string get_base_filename(const std::string &filename); +std::string get_path_relative_to(const std::string &referencefile, + const std::string &relativepath); +std::string catpath(const std::string &first, const std::string &second); +std::string canonicalise_file_separator(const std::string &path); + bool check_dir(const std::string &what, std::string &dir, bool silent = false); bool travel_load_map( branch_type branch, int absdepth ); diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc index 5b8ecad4f2..02e74c0a30 100644 --- a/crawl-ref/source/initfile.cc +++ b/crawl-ref/source/initfile.cc @@ -892,6 +892,9 @@ void game_options::reset_options() // Setup travel information. What's a better place to do this? initialise_travel(); + + // Forget any files we remembered as included. + included.clear(); } void game_options::clear_cset_overrides() @@ -1080,53 +1083,85 @@ void game_options::add_cset_override(char_set_type set, dungeon_char_type dc, cset_override[set][dc] = symbol; } -// returns where the init file was read from -std::string read_init_file(bool runscript) +static std::string _find_crawlrc() { const char* locations_data[][2] = { - { SysEnv.crawl_rc.c_str(), "" }, { SysEnv.crawl_dir.c_str(), "init.txt" }, #ifdef MULTIUSER - { SysEnv.home.c_str(), "/.crawlrc" }, + { SysEnv.home.c_str(), ".crawlrc" }, { SysEnv.home.c_str(), "init.txt" }, #endif +#ifndef DATA_DIR_PATH { "", "init.txt" }, -#ifdef WIN32CONSOLE - { "", ".crawlrc" }, - { "", "_crawlrc" }, + { "..", "init.txt" }, #endif { NULL, NULL } // placeholder to mark end }; - Options.reset_options(); + // We'll look for these files in any supplied -rcdirs. + static const char *rc_dir_filenames[] = { + ".crawlrc", "init.txt" + }; + + // -rc option always wins. + if (!SysEnv.crawl_rc.empty()) + return (SysEnv.crawl_rc); + + // If we have any rcdirs, look in them for files from the + // rc_dir_names list. + for (int i = 0, size = SysEnv.rcdirs.size(); i < size; ++i) + { + for (unsigned n = 0; n < ARRAYSZ(rc_dir_filenames); ++n) + { + const std::string rc( + catpath(SysEnv.rcdirs[i], rc_dir_filenames[n])); + if (file_exists(rc)) + return (rc); + } + } - FILE* f = NULL; - char name_buff[kPathLen]; // Check all possibilities for init.txt - for ( int i = 0; f == NULL && locations_data[i][1] != NULL; ++i ) + for ( int i = 0; locations_data[i][1] != NULL; ++i ) { // Don't look at unset options if ( locations_data[i][0] != NULL ) { - snprintf( name_buff, sizeof name_buff, "%s%s", - locations_data[i][0], locations_data[i][1] ); - f = fopen( name_buff, "r" ); + const std::string rc = + catpath(locations_data[i][0], locations_data[i][1]); + if (file_exists(rc)) + return (rc); } } + return (""); +} + +// Returns an error message if the init.txt was not found. +std::string read_init_file(bool runscript) +{ + Options.reset_options(); + + const std::string init_file_name( _find_crawlrc() ); + + FILE* f = fopen(init_file_name.c_str(), "r"); if ( f == NULL ) { + if (!init_file_name.empty()) + return make_stringf("(\"%s\" is not readable)", + init_file_name.c_str()); + #ifdef MULTIUSER - return "not found (~/.crawlrc missing)"; + return "(~/.crawlrc missing)"; #else - return "not found (init.txt missing from current directory)"; + return "(no init.txt in current directory)"; #endif } + Options.filename = init_file_name; read_options(f, runscript); fclose(f); - return std::string(name_buff); -} // end read_init_file() + return (""); +} void read_startup_prefs() { @@ -1580,6 +1615,23 @@ void game_options::set_option_fragment(const std::string &s) } } +bool game_options::include_file_directive(const std::string &line, + bool runscript) +{ + const std::string prefix = "include "; + if (line.find(prefix) == std::string::npos) + return (false); + + std::string include_line = trimmed_string(line); + if (include_line.find(prefix) == 0) + { + include(trimmed_string(include_line.substr(prefix.length())), + true, runscript); + return (true); + } + return (false); +} + void game_options::read_option_line(const std::string &str, bool runscript) { #define BOOL_OPTION_NAMED(_opt_str, _opt_var) \ @@ -1634,6 +1686,11 @@ void game_options::read_option_line(const std::string &str, bool runscript) bool plus_equal = false; bool minus_equal = false; + // If the user asked us to include a file, don't try to process the line + // as an option. + if (include_file_directive(str, runscript)) + return; + const int first_equals = str.find('='); // all lines with no equal-signs we ignore @@ -2033,12 +2090,15 @@ void game_options::read_option_line(const std::string &str, bool runscript) field.c_str() ); } } + // If DATA_DIR_PATH is set, don't set crawl_dir from .crawlrc. +#ifndef DATA_DIR_PATH else if (key == "crawl_dir") { // We shouldn't bother to allocate this a second time // if the user puts two crawl_dir lines in the init file. SysEnv.crawl_dir = field; } +#endif else if (key == "race") { race = _str_to_race( field ); @@ -2592,7 +2652,9 @@ void game_options::read_option_line(const std::string &str, bool runscript) } else if (key == "additional_macro_file") { - additional_macro_files.push_back(orig_field); + const std::string resolved = resolve_include(orig_field, "macro "); + if (!resolved.empty()) + additional_macro_files.push_back(resolved); } #ifdef USE_TILE else if (key == "tile_show_items") @@ -2718,6 +2780,128 @@ void game_options::read_option_line(const std::string &str, bool runscript) } } +// Checks an include file name for safety and resolves it to a readable path. +// If safety check fails, throws a string with the reason for failure. +// If file cannot be resolved, returns the empty string (this does not throw!) +// If file can be resolved, returns the resolved path. +std::string game_options::resolve_include( + std::string parent_file, + std::string included_file, + const std::vector *rcdirs) + + throw (std::string) +{ + // Before we start, make sure we convert forward slashes to the platform's + // favoured file separator. + parent_file = canonicalise_file_separator(parent_file); + included_file = canonicalise_file_separator(included_file); + + // How we resolve include paths: + // 1. If it's an absolute path, use it directly. + // 2. Try the name relative to the parent filename, if supplied. + // 3. Try the name relative to any of the provided rcdirs. + // 4. Try locating the name as a regular data file (also checks for the + // file name relative to the current directory). + // 5. Fail, and return empty string. + + assert_read_safe_path(included_file); + + // There's only so much you can do with an absolute path. + // Note: absolute paths can only get here if we're not on a + // multiuser system. On multiuser systems assert_read_safe_path() + // will throw an exception if it sees absolute paths. + if (is_absolute_path(included_file)) + return (file_exists(included_file)? included_file : ""); + + if (!parent_file.empty()) + { + const std::string candidate = + get_path_relative_to(parent_file, included_file); + if (file_exists(candidate)) + return (candidate); + } + + if (rcdirs) + { + const std::vector &dirs(*rcdirs); + for (int i = 0, size = dirs.size(); i < size; ++i) + { + const std::string candidate( catpath(dirs[i], included_file) ); + if (file_exists(candidate)) + return (candidate); + } + } + + return datafile_path(included_file, false, true); +} + +std::string game_options::resolve_include( + const std::string &file, + const char *type) +{ + try + { + const std::string resolved = + resolve_include(this->filename, file, &SysEnv.rcdirs); + + if (resolved.empty()) + report_error( + make_stringf("Cannot find %sfile \"%s\".", + type, file.c_str())); + return (resolved); + } + catch (const std::string &err) + { + report_error( + make_stringf("Cannot include %sfile: %s", type, err.c_str())); + return ""; + } +} + +bool game_options::was_included(const std::string &file) const +{ + return (included.find(file) != included.end()); +} + +void game_options::include(const std::string &rawfilename, + bool resolve, + bool runscript) +{ + const std::string include_file = + resolve ? resolve_include(rawfilename) : rawfilename; + + if (was_included(include_file)) + { + // Report error with rawfilename, not the resolved file name - we + // don't want to leak file paths in dgamelaunch installs. + report_error(make_stringf("Skipping previously included file: \"%s\".", + rawfilename.c_str())); + return; + } + + included.insert(include_file); + + // Change this->filename to the included filename while we're reading it. + unwind_var optfile(this->filename, include_file); + FILE* f = fopen( include_file.c_str(), "r" ); + if (f) + { + FileLineInput fl(f); + read_options(fl, runscript); + fclose(f); + } +} + +void game_options::report_error(const std::string &error) +{ + // If called before game starts, log a startup error, + // otherwise spam the warning channel. + if (crawl_state.need_save) + mprf(MSGCH_WARN, "Warning: %s", error.c_str()); + else + crawl_state.add_startup_error(error); +} + static std::string check_string(const char *s) { return (s? s : ""); @@ -2778,6 +2962,7 @@ enum commandline_option_type { CLO_PLAIN, CLO_DIR, CLO_RC, + CLO_RCDIR, CLO_TSCORES, CLO_VSCORES, CLO_SCOREFILE, @@ -2788,10 +2973,11 @@ enum commandline_option_type { CLO_NOPS }; -static const char *cmd_ops[] = { "scores", "name", "race", "class", - "pizza", "plain", "dir", "rc", "tscores", - "vscores", "scorefile", "morgue", - "macro", "mapstat" }; +static const char *cmd_ops[] = { + "scores", "name", "race", "class", "pizza", "plain", "dir", "rc", + "rcdir", "tscores", "vscores", "scorefile", "morgue", "macro", + "mapstat" +}; const int num_cmd_ops = CLO_NOPS; bool arg_seen[num_cmd_ops]; @@ -2800,6 +2986,8 @@ bool parse_args( int argc, char **argv, bool rc_only ) { set_crawl_base_dir(argv[0]); + SysEnv.rcdirs.clear(); + if (argc < 2) // no args! return (true); @@ -2991,6 +3179,15 @@ bool parse_args( int argc, char **argv, bool rc_only ) } break; + case CLO_RCDIR: + // Always parse + if (!next_is_param) + return (false); + + SysEnv.add_rcdir(next_arg); + nextUsed = true; + break; + case CLO_DIR: // ALWAYS PARSE if (!next_is_param) @@ -3077,6 +3274,18 @@ int game_options::o_colour(const char *name, int def) const return (col == -1? def : col); } +/////////////////////////////////////////////////////////////////////// +// system_environment + +void system_environment::add_rcdir(const std::string &dir) +{ + std::string cdir = canonicalise_file_separator(dir); + if (dir_exists(cdir)) + rcdirs.push_back(cdir); + else + end(1, false, "Cannot find -rcdir \"%s\"", cdir.c_str()); +} + /////////////////////////////////////////////////////////////////////// // menu_sort_condition diff --git a/crawl-ref/source/initfile.h b/crawl-ref/source/initfile.h index c700be59ef..b04b3f3850 100644 --- a/crawl-ref/source/initfile.h +++ b/crawl-ref/source/initfile.h @@ -53,10 +53,14 @@ void get_system_environment(void); struct system_environment { +public: std::string crawl_name; std::string crawl_pizza; std::string crawl_rc; std::string crawl_dir; + + std::vector rcdirs; // Directories to search for includes. + std::string morgue_dir; std::string crawl_base; // Directory from argv[0], may be used to // locate datafiles. @@ -73,6 +77,9 @@ struct system_environment std::vector cmd_args; int map_gen_iters; + +public: + void add_rcdir(const std::string &dir); }; extern system_environment SysEnv; diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc index c44b0f88a6..4f1dce7695 100644 --- a/crawl-ref/source/itemname.cc +++ b/crawl-ref/source/itemname.cc @@ -1696,6 +1696,9 @@ bool item_type_known(const object_class_type base_type, const int sub_type) return false; } +// [ds] Will the owner of this unused function step up and end its +// suffering? :P +#if 0 static bool _randart_has_known_property(const item_def &item) { for (int rap = 0; rap < RAP_NUM_PROPERTIES; rap++) @@ -1704,6 +1707,7 @@ static bool _randart_has_known_property(const item_def &item) return false; } +#endif bool item_type_tried( const item_def& item ) { diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc index 3ecbe9afd1..d1ea2d624a 100644 --- a/crawl-ref/source/mapmark.cc +++ b/crawl-ref/source/mapmark.cc @@ -762,6 +762,7 @@ void map_markers::read(reader &inf, int minorVersion) { const long cooky = unmarshallLong(inf); ASSERT(cooky == MARKERS_COOKY); + UNUSED(cooky); } const int nmarkers = unmarshallShort(inf); diff --git a/crawl-ref/source/newgame.cc b/crawl-ref/source/newgame.cc index 2b2baa873a..67b2a69516 100644 --- a/crawl-ref/source/newgame.cc +++ b/crawl-ref/source/newgame.cc @@ -102,7 +102,7 @@ #include "version.h" #include "view.h" -extern std::string init_file_location; +extern std::string init_file_error; #define MIN_START_STAT 1 @@ -2468,15 +2468,31 @@ static void _opening_screen(void) "Please consult crawl_manual.txt for instructions and legal details." "" EOL; - const bool init_found = - (init_file_location.find("not found") == std::string::npos); + const bool init_found = init_file_error.empty(); if (!init_found) - msg += "Init file "; + msg += "No init file "; else - msg += "Init file read: "; + msg += "(Read options from "; + + if (init_found) + { +#ifdef DGAMELAUNCH + // For dgl installs, show only the last segment of the .crawlrc + // file name so that we don't leak details of the directory + // structure to (untrusted) users. + msg += get_base_filename(Options.filename); +#else + msg += Options.filename; +#endif + msg += ".)"; + } + else + { + msg += init_file_error; + msg += ", using defaults."; + } - msg += init_file_location; msg += EOL; formatted_string::parse_string(msg).display(); -- cgit v1.2.3-54-g00ecf