20 #define GETTEXT_DOMAIN "wesnoth-lib" 34 #include <boost/algorithm/string.hpp> 35 #include <boost/filesystem.hpp> 36 #include <boost/filesystem/fstream.hpp> 37 #include <boost/iostreams/device/file_descriptor.hpp> 38 #include <boost/iostreams/stream.hpp> 44 #include <boost/locale.hpp> 51 #ifndef VOLUME_NAME_NONE 52 #define VOLUME_NAME_NONE 0x4 61 #if defined(__APPLE__) && defined(__MACH__) && defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) 63 #define WESNOTH_BOOST_OS_IOS (__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__*1000) 64 #include <SDL2/SDL_filesystem.h> 70 #define DBG_FS LOG_STREAM(debug, log_filesystem) 71 #define LOG_FS LOG_STREAM(info, log_filesystem) 72 #define WRN_FS LOG_STREAM(warn, log_filesystem) 73 #define ERR_FS LOG_STREAM(err, log_filesystem) 75 namespace bfs = boost::filesystem;
76 using boost::system::error_code;
81 const std::string maincfg_filename =
"_main.cfg";
82 const std::string finalcfg_filename =
"_final.cfg";
83 const std::string initialcfg_filename =
"_initial.cfg";
86 class customcodecvt :
public std::codecvt<wchar_t , char , std::mbstate_t>
90 template<
typename char_t_to>
91 struct customcodecvt_do_conversion_writer
93 customcodecvt_do_conversion_writer(char_t_to*& _to_next, char_t_to* _to_end)
102 bool can_push(std::size_t count)
const 104 return static_cast<std::size_t
>(to_end - to_next) > count;
107 void push(char_t_to val)
109 assert(to_next != to_end);
114 template<
typename char_t_from,
typename char_t_to>
115 static void customcodecvt_do_conversion(std::mbstate_t& ,
116 const char_t_from* from,
117 const char_t_from* from_end,
118 const char_t_from*& from_next,
128 customcodecvt_do_conversion_writer<char_t_to> writer(to_next, to_end);
130 while(from_next != from_end) {
137 int do_encoding()
const noexcept
143 bool do_always_noconv()
const noexcept
148 int do_length(std::mbstate_t& ,
const char* ,
const char* , std::size_t )
const 151 throw "Not supported";
154 std::codecvt_base::result unshift(
155 std::mbstate_t& ,
char* ,
char* ,
char*& )
const 158 throw "Not supported";
162 std::codecvt_base::result do_in(std::mbstate_t& state,
164 const char* from_end,
165 const char*& from_next,
168 wchar_t*& to_next)
const 171 customcodecvt_do_conversion<char, wchar_t>(state, from, from_end, from_next, to, to_end, to_next);
174 return std::codecvt_base::error;
177 return std::codecvt_base::ok;
180 std::codecvt_base::result do_out(std::mbstate_t& state,
182 const wchar_t* from_end,
183 const wchar_t*& from_next,
186 char*& to_next)
const 189 customcodecvt_do_conversion<wchar_t, char>(state, from, from_end, from_next, to, to_end, to_next);
192 return std::codecvt_base::error;
195 return std::codecvt_base::ok;
209 utf8_loc = std::locale(utf8_loc,
new customcodecvt());
211 boost::filesystem::path::imbue(utf8_loc);
215 static static_runner static_bfs_path_imbuer;
217 bool is_filename_case_correct(
const std::string& fname,
const boost::iostreams::file_descriptor_source& fd)
219 wchar_t real_path[MAX_PATH];
220 GetFinalPathNameByHandleW(fd.handle(), real_path, MAX_PATH - 1, VOLUME_NAME_NONE);
227 bool is_filename_case_correct(
const std::string& ,
const boost::iostreams::file_descriptor_source& )
241 vec->push_back(file.generic_string());
243 vec->push_back(file.filename().generic_string());
250 return ec && ec != boost::system::errc::no_such_file_or_directory;
258 LOG_FS <<
"Failed to check if " << fpath.string() <<
" is a directory: " << ec.message();
269 ERR_FS <<
"Failed to check existence of file " << fpath.string() <<
": " << ec.message();
280 bfs::create_directory(dirpath, ec);
283 ERR_FS <<
"Failed to create directory " << dirpath.string() <<
": " << ec.message();
291 ERR_FS <<
"Could not open or create directory " << dirpath.string();
292 return std::string();
301 bfs::file_status
fs = bfs::status(dirpath, ec);
304 ERR_FS <<
"Failed to retrieve file status for " << dirpath.string() <<
": " << ec.message();
307 DBG_FS <<
"directory " << dirpath.string() <<
" exists, not creating";
310 ERR_FS <<
"cannot create directory " << dirpath.string() <<
"; file exists";
314 bool created = bfs::create_directory(dirpath, ec);
316 ERR_FS <<
"Failed to create directory " << dirpath.string() <<
": " << ec.message();
324 DBG_FS <<
"creating recursive directory: " << dirpath.string();
326 if(dirpath.empty()) {
331 bfs::file_status
fs = bfs::status(dirpath);
334 ERR_FS <<
"Failed to retrieve file status for " << dirpath.string() <<
": " << ec.message();
345 ERR_FS <<
"Could not create parents to " << dirpath.string();
351 std::vector<std::string>* files,
352 std::vector<std::string>* dirs,
363 get_files_in_dir(absolute_dir.string(), files, dirs, mode, filter, reorder, checksum);
370 if(reorder == reorder_mode::DO_REORDER) {
371 LOG_FS <<
"searching for _main.cfg in directory " << dir;
372 const bfs::path maincfg = dirpath / maincfg_filename;
375 LOG_FS <<
"_main.cfg found : " << maincfg;
376 push_if_exists(files, maincfg, mode == name_mode::ENTIRE_FILE_PATH);
382 bfs::directory_iterator di(dirpath, ec);
383 bfs::directory_iterator end;
390 for(; di != end; ++di) {
391 bfs::file_status st = di->status(ec);
393 LOG_FS <<
"Failed to get file status of " << di->path().string() <<
": " << ec.message();
397 if(st.type() == bfs::regular_file) {
399 std::string basename = di->path().filename().string();
400 if(filter == filter_mode::SKIP_PBL_FILES &&
looks_like_pbl(basename))
402 if(!basename.empty() && basename[0] ==
'.')
406 push_if_exists(files, di->path(), mode == name_mode::ENTIRE_FILE_PATH);
408 if(checksum !=
nullptr) {
409 std::time_t mtime = bfs::last_write_time(di->path(), ec);
411 LOG_FS <<
"Failed to read modification time of " << di->path().string() <<
": " << ec.message();
412 }
else if(mtime > checksum->
modified) {
418 LOG_FS <<
"Failed to read filesize of " << di->path().string() <<
": " << ec.message();
425 }
else if(st.type() == bfs::directory_file) {
426 std::string basename = di->path().filename().string();
428 if(!basename.empty() && basename[0] ==
'.') {
432 if(filter == filter_mode::SKIP_MEDIA_DIR && (basename ==
"images" || basename ==
"sounds")) {
436 const bfs::path inner_main(di->path() / maincfg_filename);
437 bfs::file_status main_st = bfs::status(inner_main, ec);
440 LOG_FS <<
"Failed to get file status of " << inner_main.string() <<
": " << ec.message();
441 }
else if(reorder == reorder_mode::DO_REORDER && main_st.type() == bfs::regular_file) {
442 LOG_FS <<
"_main.cfg found : " 443 << (mode == name_mode::ENTIRE_FILE_PATH ? inner_main.string() : inner_main.filename().string());
444 push_if_exists(files, inner_main, mode == name_mode::ENTIRE_FILE_PATH);
446 push_if_exists(dirs, di->path(), mode == name_mode::ENTIRE_FILE_PATH);
451 if(files !=
nullptr) {
452 std::sort(files->begin(), files->end());
455 if(dirs !=
nullptr) {
456 std::sort(dirs->begin(), dirs->end());
459 if(files !=
nullptr && reorder == reorder_mode::DO_REORDER) {
461 for(
unsigned int i = 0;
i < files->size();
i++) {
462 if(
ends_with((*files)[
i],
"/" + finalcfg_filename)) {
463 files->push_back((*files)[i]);
464 files->erase(files->begin() +
i);
471 for(
unsigned int i = 0;
i < files->size();
i++)
472 if(
ends_with((*files)[
i],
"/" + initialcfg_filename)) {
477 std::string initialcfg = (*files)[foundit];
478 for(
unsigned int i = foundit; i > 0; i--)
479 (*files)[
i] = (*files)[i - 1];
480 (*files)[0] = initialcfg;
492 std::string next_filename;
496 std::stringstream filename;
501 filename.setf(std::ios_base::right);
502 filename << counter << extension;
505 next_filename = filename.str();
506 }
while(
file_exists(next_filename) && counter < 1000);
508 return next_filename;
515 std::ostringstream
s;
522 static std::string suffix;
534 #if defined(__APPLE__) && !defined(__IPHONEOS__) 540 static void migrate_apple_config_directory_for_unsandboxed_builds()
542 const char* home_str = getenv(
"HOME");
543 bfs::path home = home_str ? home_str :
".";
548 boost::filesystem::path new_saves_dir = home /
"Library/Containers/org.wesnoth.Wesnoth/Data/Library/Application Support/Wesnoth_";
553 LOG_FS <<
"Apple developer's userdata migration: symlinking " << old_saves_dir.string() <<
" to " << new_saves_dir.string();
554 bfs::create_symlink(new_saves_dir, old_saves_dir);
555 }
else if(!bfs::symbolic_link_exists(old_saves_dir)) {
556 ERR_FS <<
"Apple developer's userdata migration: Problem! Old (non-containerized) directory " << old_saves_dir.string() <<
" is not a symlink. Your savegames are scattered around 2 locations.";
566 #if defined(__APPLE__) && !defined(__IPHONEOS__) 567 migrate_apple_config_directory_for_unsandboxed_builds();
574 ERR_FS <<
"could not open or create user data directory at " << user_data_dir.string();
600 static bool is_path_relative_to_cwd(
const std::string& str)
608 return *p.begin() ==
"." || *p.begin() ==
"..";
614 [[maybe_unused]]
bool relative_ok =
false;
616 #ifdef PREFERENCES_DIR 617 if(newprefdir.empty()) {
618 newprefdir = PREFERENCES_DIR;
624 if(newprefdir.size() > 2 && newprefdir[1] ==
':') {
626 user_data_dir = newprefdir;
627 }
else if(is_path_relative_to_cwd(newprefdir)) {
629 user_data_dir =
get_cwd() +
"/" + newprefdir;
631 if(newprefdir.empty()) {
634 #ifdef PREFERENCES_DIR 635 if (newprefdir != PREFERENCES_DIR)
642 _(
"Use an absolute path, or a relative path that starts with a period and a backslash"));
646 PWSTR docs_path =
nullptr;
647 HRESULT res = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_CREATE,
nullptr, &docs_path);
653 ERR_FS <<
"Could not determine path to user's Documents folder! (" << std::hex <<
"0x" << res << std::dec <<
") " 654 <<
"User config/data directories may be unavailable for " 655 <<
"this session. Please report this as a bug.";
661 user_data_dir = games_path / newprefdir;
664 CoTaskMemFree(docs_path);
671 #ifdef WESNOTH_BOOST_OS_IOS 672 char *sdl_pref_path = SDL_GetPrefPath(
"wesnoth.org",
"iWesnoth");
674 backupprefdir = std::string(sdl_pref_path) + backupprefdir;
675 SDL_free(sdl_pref_path);
680 const char* home_str = getenv(
"HOME");
682 if(newprefdir.empty()) {
683 char const* xdg_data = getenv(
"XDG_DATA_HOME");
684 if(!xdg_data || xdg_data[0] ==
'\0') {
686 newprefdir = backupprefdir;
690 user_data_dir = home_str;
691 user_data_dir /=
".local/share";
693 user_data_dir = xdg_data;
696 user_data_dir /=
"wesnoth";
700 bfs::path home = home_str ? home_str :
".";
702 if(newprefdir[0] ==
'/') {
703 user_data_dir = newprefdir;
710 _(
"Use absolute paths. Relative paths are deprecated because they are interpreted relative to $HOME"));
712 user_data_dir = home / newprefdir;
716 if(newprefdir.empty()) {
717 newprefdir = backupprefdir;
721 const char* home_str = getenv(
"HOME");
722 bfs::path home = home_str ? home_str :
".";
724 if(newprefdir[0] ==
'/') {
725 user_data_dir = newprefdir;
732 _(
"Use absolute paths. Relative paths are deprecated because they are interpreted relative to $HOME"));
734 user_data_dir = home / newprefdir;
740 user_data_dir =
normalize_path(user_data_dir.string(),
true,
true);
745 user_config_dir = newconfig;
747 ERR_FS <<
"could not open or create user config directory at " << user_config_dir.string();
758 cache_dir = newcache;
760 ERR_FS <<
"could not open or create cache directory at " << cache_dir.string() <<
'\n';
771 if(user_data_dir.empty()) {
780 if(user_config_dir.empty()) {
781 #if defined(_X11) && !defined(PREFERENCES_DIR) 782 char const* xdg_config = getenv(
"XDG_CONFIG_HOME");
784 if(!xdg_config || xdg_config[0] ==
'\0') {
785 xdg_config = getenv(
"HOME");
788 return user_config_dir.string();
791 user_config_dir = xdg_config;
792 user_config_dir /=
".config";
794 user_config_dir = xdg_config;
797 user_config_dir /=
"wesnoth";
804 return user_config_dir.string();
819 if(cache_dir.empty()) {
820 #if defined(_X11) && !defined(PREFERENCES_DIR) 821 char const* xdg_cache = getenv(
"XDG_CACHE_HOME");
823 if(!xdg_cache || xdg_cache[0] ==
'\0') {
824 xdg_cache = getenv(
"HOME");
827 return cache_dir.string();
830 cache_dir = xdg_cache;
831 cache_dir /=
".cache";
833 cache_dir = xdg_cache;
836 cache_dir /=
"wesnoth";
843 return cache_dir.string();
848 #if !defined(_WIN32) && !defined(_X11) && !defined(__APPLE__) 855 if(w_ver.major_version() != 1 || ms_ver.major_version() != 1) {
860 std::vector<other_version_dir> result;
863 for(
auto minor = w_ver.minor_version() + 4; minor >= ms_ver.minor_version(); --minor) {
864 if(minor == w_ver.minor_version())
869 version.set_minor_version(minor);
886 #elif defined(__APPLE__) 891 result.emplace_back(suffix, path.string());
905 ERR_FS <<
"Failed to get current directory: " << ec.message();
909 return cwd.generic_string();
918 ERR_FS <<
"Failed to set current directory: " << ec.message();
921 LOG_FS <<
"Process working directory set to " << dir;
930 wchar_t process_path[MAX_PATH];
931 SetLastError(ERROR_SUCCESS);
933 GetModuleFileNameW(
nullptr, process_path, MAX_PATH);
935 if(GetLastError() != ERROR_SUCCESS) {
940 return exe.parent_path().string();
945 bfs::path exe = bfs::read_symlink(self_exe, ec);
947 return std::string();
950 return exe.parent_path().string();
960 bool created = bfs::create_directory(
bfs::path(dirname), ec);
962 ERR_FS <<
"Failed to create directory " << dirname <<
": " << ec.message();
971 std::vector<std::string> files;
972 std::vector<std::string> dirs;
975 get_files_in_dir(dirname, &files, &dirs, name_mode::ENTIRE_FILE_PATH, keep_pbl ? filter_mode::SKIP_PBL_FILES : filter_mode::NO_FILTER);
978 for(
const std::string&
f : files) {
981 LOG_FS <<
"remove(" <<
f <<
"): " << ec.message();
988 for(
const std::string&
d : dirs) {
999 LOG_FS <<
"remove(" << dirname <<
"): " << ec.message();
1012 ERR_FS <<
"Could not delete file " << filename <<
": " << ec.message();
1021 std::stringstream ss;
1028 LOG_FS <<
"Streaming " << fname <<
" for reading.";
1031 ERR_FS <<
"Trying to open file with empty name.";
1033 s->clear(std::ios_base::failbit);
1040 boost::iostreams::file_descriptor_source fd(
bfs::path(fname), std::ios_base::binary);
1043 if(!fd.is_open() && treat_failure_as_error) {
1044 ERR_FS <<
"Could not open '" << fname <<
"' for reading.";
1045 }
else if(!is_filename_case_correct(fname, fd)) {
1046 ERR_FS <<
"Not opening '" << fname <<
"' due to case mismatch.";
1048 s->clear(std::ios_base::failbit);
1052 return std::make_unique<boost::iostreams::stream<boost::iostreams::file_descriptor_source>>(fd, 4096, 0);
1053 }
catch(
const std::exception&) {
1054 if(treat_failure_as_error) {
1055 ERR_FS <<
"Could not open '" << fname <<
"' for reading.";
1059 s->clear(std::ios_base::failbit);
1066 LOG_FS <<
"streaming " << fname <<
" for writing.";
1068 boost::iostreams::file_descriptor_sink fd(
bfs::path(fname), mode);
1069 return std::make_unique<boost::iostreams::stream<boost::iostreams::file_descriptor_sink>>(fd, 4096, 0);
1070 }
catch(
const BOOST_IOSTREAMS_FAILURE&
e) {
1073 error_code ec_unused;
1074 if(create_directory && bfs::create_directories(
bfs::path(fname).parent_path(), ec_unused)) {
1083 void write_file(
const std::string& fname,
const std::string&
data, std::ios_base::openmode mode)
1086 os->exceptions(std::ios_base::goodbit);
1088 const std::size_t block_size = 4096;
1089 char buf[block_size];
1091 for(std::size_t
i = 0;
i < data.size();
i += block_size) {
1092 const std::size_t bytes = std::min<std::size_t>(block_size, data.size() -
i);
1093 std::copy(data.begin() +
i, data.begin() +
i + bytes, buf);
1095 os->write(buf, bytes);
1097 throw io_exception(
"Error writing to file: '" + fname +
"'");
1102 void copy_file(
const std::string& src,
const std::string& dest)
1130 std::time_t mtime = bfs::last_write_time(
bfs::path(fname), ec);
1132 LOG_FS <<
"Failed to read modification time of " << fname <<
": " << ec.message();
1140 return bfs::path(filename).extension() ==
".gz";
1145 return bfs::path(filename).extension() ==
".bz2";
1153 LOG_FS <<
"Failed to read filesize of " << fname <<
": " << ec.message();
1155 }
else if(size > INT_MAX) {
1165 uintmax_t size_sum = 0;
1167 for(bfs::recursive_directory_iterator
i(p), end;
i != end && !ec; ++
i) {
1168 if(bfs::is_regular_file(
i->path())) {
1174 LOG_FS <<
"Failed to read directorysize of " << pname <<
": " << ec.message();
1176 }
else if(size_sum > INT_MAX) {
1183 std::string
base_name(
const std::string& file,
const bool remove_extension)
1185 if(!remove_extension) {
1186 return bfs::path(file).filename().string();
1194 return bfs::path(file).parent_path().string();
1207 p =
p.parent_path();
1212 }
while(ec && !
is_root(
p.string()));
1214 return ec ?
"" :
p.string();
1220 const std::string
s = std::string(1, c);
1221 return sep ==
bfs::path(s).make_preferred();
1226 return bfs::path::preferred_separator;
1233 const bfs::path&
p = bfs::canonical(path, ec);
1234 return ec ? false : !p.has_parent_path();
1257 const std::wstring& wpath =
bfs::path{path}.make_preferred().wstring();
1258 return PathIsRootW(wpath.c_str()) == TRUE;
1264 return bfs::path{path}.root_name().string();
1272 std::string
normalize_path(
const std::string& fpath,
bool normalize_separators,
bool resolve_dot_entries)
1279 bfs::path p = resolve_dot_entries ? bfs::canonical(fpath, ec) : bfs::absolute(fpath);
1285 if(normalize_separators) {
1286 return p.make_preferred().string();
1306 std::set<std::string> binary_paths;
1308 typedef std::map<std::string, std::vector<std::string>> paths_map;
1309 paths_map binary_paths_cache;
1315 if(binary_paths.empty()) {
1316 binary_paths.insert(
"");
1320 binary_paths_manager::binary_paths_manager()
1342 std::string
path = bp[
"path"].str();
1343 if(path.find(
"..") != std::string::npos) {
1344 ERR_FS <<
"Invalid binary path '" << path <<
"'";
1348 if(!path.empty() && path.back() !=
'/')
1350 if(binary_paths.count(path) == 0) {
1351 binary_paths.insert(path);
1359 binary_paths_cache.clear();
1361 for(
const std::string&
p :
paths_) {
1362 binary_paths.erase(
p);
1368 binary_paths_cache.clear();
1373 DBG_FS <<
"Looking for '" << filename_str <<
"'.";
1375 if(filename_str.empty()) {
1376 LOG_FS <<
" invalid filename";
1380 if(filename_str.find(
"..") != std::string::npos) {
1381 ERR_FS <<
"Illegal path '" << filename_str <<
"' (\"..\" not allowed).";
1385 if(filename_str.find(
'\\') != std::string::npos) {
1386 ERR_FS <<
"Illegal path '" << filename_str
1387 << R
"end(' ("\" not allowed, for compatibility with GNU/Linux and macOS).)end"; 1394 ERR_FS <<
"Illegal path '" << filename_str <<
"' (blacklisted filename).";
1398 if(std::any_of(filepath.begin(), filepath.end(),
1400 ERR_FS <<
"Illegal path '" << filename_str <<
"' (blacklisted directory name).";
1413 const paths_map::const_iterator itor = binary_paths_cache.find(type);
1414 if(itor != binary_paths_cache.end()) {
1415 return itor->second;
1418 if(type.find(
"..") != std::string::npos) {
1420 ERR_FS <<
"Invalid WML type '" << type <<
"' for binary paths";
1421 static std::vector<std::string> dummy;
1425 std::vector<std::string>& res = binary_paths_cache[
type];
1429 for(
const std::string&
path : binary_paths) {
1456 std::string::size_type pos = filename.rfind(
"../");
1457 if(pos != std::string::npos) {
1463 return std::string();
1471 DBG_FS <<
" checking '" << bp <<
"'";
1474 DBG_FS <<
" found at '" << bpath.string() <<
"'";
1475 if(result.empty()) {
1476 result = bpath.string();
1478 WRN_FS <<
"Conflicting files in binary_path: '" << result
1479 <<
"' and '" << bpath.string() <<
"'";
1491 return std::string();
1497 DBG_FS <<
" checking '" << bp <<
"'";
1499 DBG_FS <<
" found at '" << bpath.string() <<
"'";
1500 return bpath.string();
1505 return std::string();
1511 return std::string();
1519 if(filename[0] ==
'~') {
1521 DBG_FS <<
" trying '" << result.string() <<
"'";
1522 }
else if(*fpath.begin() ==
".") {
1523 if(!current_dir.empty()) {
1538 DBG_FS <<
" found: '" << result.string() <<
"'";
1541 return result.string();
1546 bfs::path::iterator fi = full.begin(), fe = full.end(), pi = prefix.begin(), pe = prefix.end();
1547 while(fi != fe && pi != pe && *fi == *pi) {
1568 if(!partial.empty()) {
1569 return "~" + partial.generic_string();
1573 if(!partial.empty()) {
1574 return partial.generic_string();
1584 if(full_path.empty()) {
1585 return full_path.generic_string();
1589 if(!partial.empty()) {
1590 return partial.generic_string();
1594 if(!partial.empty()) {
1595 return partial.generic_string();
1598 return full_path.generic_string();
1603 const std::string real_program_name(program_name
1618 const char* user_name = getenv(
"USERNAME");
1620 const char* user_name = getenv(
"USER");
1624 if(user_name !=
nullptr) {
1625 boost::replace_all(canonicalized, user_name,
"USER");
1628 return canonicalized;
1638 const std::size_t pos_ext = base.rfind(
".");
1640 std::string loc_base;
1641 if(pos_ext != std::string::npos) {
1642 loc_base = base.substr(0, pos_ext) + suff + base.substr(pos_ext);
1644 loc_base = base + suff;
1657 std::vector<std::string> langs =
utils::split(
_(
"language code for localized resources^en_US"));
1662 langs.push_back(
"en_US");
1663 for(
const std::string& lang : langs) {
1664 std::string loc_file = dir +
"/" +
"l10n" +
"/" + lang +
"/" + loc_base;
std::string get_binary_dir_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual directory of a given type or an empty string if the directory i...
void remove()
Removes a tip.
bool delete_directory(const std::string &dirname, const bool keep_pbl)
static void push_if_exists(std::vector< std::string > *vec, const bfs::path &file, bool full)
std::string get_program_invocation(const std::string &program_name)
Returns the appropriate invocation for a Wesnoth-related binary, assuming that it is located in the s...
std::string get_next_filename(const std::string &name, const std::string &extension)
Get the next free filename using "name + number (3 digits) + extension" maximum 1000 files then start...
bool delete_file(const std::string &filename)
bool looks_like_pbl(const std::string &file)
void set_user_data_dir(std::string newprefdir)
config_array_view child_range(config_key_type key) const
static bool file_exists(const bfs::path &fpath)
bool ends_with(const std::string &str, const std::string &suffix)
void finish_log_file_setup()
Relocates the stdout+stderr log file to the user data directory.
void set_major_version(unsigned int)
Sets the major version number.
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
std::string get_logs_dir()
static void init_binary_paths()
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
std::string get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type or an empty string if the file isn't prese...
std::string normalize_path(const std::string &fpath, bool normalize_separators, bool resolve_dot_entries)
Returns the absolute path of a file.
void set_cache_dir(const std::string &newcachedir)
static std::string _(const char *str)
Definitions for the interface to Wesnoth Markup Language (WML).
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
std::string get_independent_binary_file_path(const std::string &type, const std::string &filename)
Returns an asset path to filename for binary path-independent use in saved games. ...
void clear_binary_paths_cache()
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
static bool is_legal_file(const std::string &filename_str)
bool match_file(const std::string &name) const
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
bool create_directory_if_missing_recursive(const std::string &dirname)
Creates a recursive directory tree if it does not exist already.
bool create_directory_if_missing(const std::string &dirname)
Creates a directory if it does not exist already.
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
static bfs::path user_config_dir
void read(config &cfg, std::istream &in, abstract_validator *validator)
static bool is_directory_internal(const bfs::path &fpath)
static void set_cache_path(bfs::path newcache)
std::string get_user_data_dir()
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
std::string root_name(const std::string &path)
Returns the name of the root device if included in the given path.
std::string nearest_extant_parent(const std::string &file)
Finds the nearest parent in existence for a file or directory.
void rotate_logs(const std::string &log_dir)
Deletes old log files from the log directory.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::unique_ptr< std::istream > scoped_istream
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
const std::string & get_version_path_suffix()
static bfs::path user_data_dir
std::string sanitize_path(const std::string &path)
Sanitizes a path to remove references to the user's name.
std::string get_dir(const std::string &dir)
std::string read_file(const std::string &fname)
Basic disk I/O - read file.
bool is_path_sep(char c)
Returns whether c is a path separator.
std::unique_ptr< std::ostream > scoped_ostream
bool is_gzip_file(const std::string &filename)
Returns true if the file ends with '.gz'.
std::string get_cache_dir()
void write_file(const std::string &fname, const std::string &data, std::ios_base::openmode mode)
Throws io_exception if an error occurs.
const std::vector< std::string > & get_binary_paths(const std::string &type)
Returns a vector with all possible paths to a given type of binary, e.g.
std::string get_exe_dir()
Log file control routines for Windows.
void set_user_config_dir(const std::string &newconfigdir)
bool is_relative(const std::string &path)
Returns whether the path seems to be relative.
int dir_size(const std::string &pname)
Returns the sum of the sizes of the files contained in a directory.
std::string get_wml_location(const std::string &filename, const std::string ¤t_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn't pres...
std::vector< std::string > paths_
void copy_file(const std::string &src, const std::string &dest)
Read a file and then writes it back out.
An exception object used when an IO error occurs.
static map_location::DIRECTION s
bool make_directory(const std::string &dirname)
bool is_root(const std::string &path)
Returns whether the path is the root of the file hierarchy.
Declarations for File-IO.
std::string get_localized_path(const std::string &file, const std::string &suff)
Returns the localized version of the given filename, if it exists.
const version_info wesnoth_version(VERSION)
rng * generator
This generator is automatically synced during synced context.
Represents version numbers.
char path_separator()
Returns the standard path separator for the current platform.
static bfs::path cache_dir
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
int file_size(const std::string &fname)
Returns the size of a file, or -1 if the file doesn't exist.
bool set_cwd(const std::string &dir)
std::string get_user_config_dir()
void set_paths(const game_config_view &cfg)
bool is_bzip2_file(const std::string &filename)
Returns true if the file ends with '.bz2'.
std::time_t file_modified_time(const std::string &fname)
Get the modification time of a file.
std::vector< std::string > split(const config_attribute_value &val)
static bool error_except_not_found(const error_code &ec)
static void set_user_config_path(bfs::path newconfig)
static bfs::path subtract_path(const bfs::path &full, const bfs::path &prefix)
Standard logging facilities (interface).
std::vector< other_version_dir > find_other_version_saves_dirs()
Searches for directories containing saves created by other versions of Wesnoth.
There are still moves and/or attacks possible, but the unit doesn't fit in the "unmoved" status...
bool match_dir(const std::string &name) const
A config object defines a single node in a WML file, with access to child nodes.
static lg::log_domain log_filesystem("filesystem")
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
static void setup_user_data_dir()
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
std::string::const_iterator iterator
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
std::string wesnoth_program_dir
static const bfs::path & get_user_data_path()
static const blacklist_pattern_list default_blacklist