From 1058f839e5cb71c7cd1961328c8fc5f177387ba0 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 09:27:42 -0500 Subject: [PATCH 01/20] use `std::filesystem::path` Recode most uses of `std::string` to represent a path name to use `std::filesystem::path` instead. Eliminate most of old crunchy filesystem module with `std::filesystem` equivalent methods some modules have also cleaned to remove `using filesystem std` and/or missing or unnecessary `#include`s note: the `atime`, `ctime`, and `filetype` methods of the `Filesystem` module have been removed because they're POSIX-specific, not supported by `std::filesystem`, and unused in DFHack --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 6 - library/Core.cpp | 129 +++++++------- library/LuaApi.cpp | 25 ++- library/PlugLoad.cpp | 6 +- library/PluginManager.cpp | 60 +++---- library/Process-linux.cpp | 2 +- library/Process-windows.cpp | 4 +- library/Types.cpp | 14 +- library/include/Console.h | 5 +- library/include/Core.h | 8 +- library/include/MemAccess.h | 3 +- library/include/PluginManager.h | 6 +- library/include/Types.h | 4 +- library/include/modules/Filesystem.h | 122 ++----------- library/modules/Filesystem.cpp | 251 ++++++++++----------------- library/modules/Persistence.cpp | 20 +-- plugins/orders.cpp | 24 +-- 18 files changed, 253 insertions(+), 437 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 6327a843b7..ed65524207 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ Template for new versions: ## Documentation ## API +- `Filesystem` module: rewritten to use C++ standard library components, for better portability ## Lua diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 0a2fdc894a..d449c8810b 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3168,12 +3168,6 @@ unless otherwise noted. specified by ``path``, or -1 if ``path`` does not exist. This depends on the system clock and should only be used locally. -* ``dfhack.filesystem.atime(path)`` -* ``dfhack.filesystem.ctime(path)`` - - Return values vary across operating systems - return the ``st_atime`` and - ``st_ctime`` fields of a C++ stat struct, respectively. - * ``dfhack.filesystem.listdir(path)`` Lists files/directories in a directory. Returns ``{}`` if ``path`` does not exist. diff --git a/library/Core.cpp b/library/Core.cpp index be53fe58fd..c4c611ee9d 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -83,8 +83,14 @@ distribution. #include #include #include +#include #include +#ifdef _WIN32 +#define NOMINMAX +#include +#endif + #ifdef LINUX_BUILD #include #endif @@ -98,15 +104,15 @@ using std::string; // FIXME: A lot of code in one file, all doing different things... there's something fishy about it. static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string *pfocus = NULL); -size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector& prefix, const std::string& folder); +size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector& prefix, const std::filesystem::path& folder); namespace DFHack { DBG_DECLARE(core,keybinding,DebugCategory::LINFO); DBG_DECLARE(core,script,DebugCategory::LINFO); -static const std::string CONFIG_PATH = "dfhack-config/"; -static const std::string CONFIG_DEFAULTS_PATH = "hack/data/dfhack-config-defaults/"; +static const std::filesystem::path CONFIG_PATH{ std::filesystem::path{} / "dfhack-config" }; +static const std::filesystem::path CONFIG_DEFAULTS_PATH{ std::filesystem::path{} / "hack" / "data" / "dfhack-config-defaults" }; class MainThread { public: @@ -511,33 +517,33 @@ bool Core::removeScriptPath(std::string path) return found; } -void Core::getScriptPaths(std::vector *dest) +void Core::getScriptPaths(std::vector *dest) { std::lock_guard lock(script_path_mutex); dest->clear(); - std::string df_path = this->p->getPath() + "/"; + std::filesystem::path df_path = this->p->getPath(); for (auto & path : script_paths[0]) dest->emplace_back(path); - dest->push_back(df_path + CONFIG_PATH + "scripts"); + dest->push_back(df_path / CONFIG_PATH / "scripts"); if (df::global::world && isWorldLoaded()) { std::string save = World::ReadWorldFolder(); if (save.size()) - dest->emplace_back(df_path + "save/" + save + "/scripts"); + dest->emplace_back(df_path / "save" / save / "scripts"); } - dest->emplace_back(df_path + "hack/scripts"); + dest->emplace_back(df_path / "hack" / "scripts"); for (auto & path : script_paths[2]) dest->emplace_back(path); for (auto & path : script_paths[1]) dest->emplace_back(path); } -std::string Core::findScript(std::string name) +std::filesystem::path Core::findScript(std::string name) { - std::vector paths; + std::vector paths; getScriptPaths(&paths); for (auto it = paths.begin(); it != paths.end(); ++it) { - std::string path = *it + "/" + name; + std::filesystem::path path = *it / name; if (Filesystem::isfile(path)) return path; } @@ -546,9 +552,8 @@ std::string Core::findScript(std::string name) bool loadScriptPaths(color_ostream &out, bool silent = false) { - using namespace std; - std::string filename(CONFIG_PATH + "script-paths.txt"); - ifstream file(filename); + std::filesystem::path filename{ CONFIG_PATH / "script-paths.txt" }; + std::ifstream file(filename); if (!file) { if (!silent) @@ -560,12 +565,12 @@ bool loadScriptPaths(color_ostream &out, bool silent = false) while (getline(file, raw)) { ++line; - istringstream ss(raw); + std::istringstream ss(raw); char ch; - ss >> skipws; + ss >> std::skipws; if (!(ss >> ch) || ch == '#') continue; - ss >> ws; // discard whitespace + ss >> std::ws; // discard whitespace std::string path; getline(ss, path); if (ch == '+' || ch == '-') @@ -857,8 +862,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s if(!plug) { - std::string lua = findScript(part + ".lua"); - if (lua.size()) + std::filesystem::path lua = findScript(part + ".lua"); + if (!lua.empty()) { res = enableLuaScript(con, part, enable); } @@ -961,7 +966,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s } con << parts[0]; bool builtin = is_builtin(con, parts[0]); - std::string lua_path = findScript(parts[0] + ".lua"); + std::filesystem::path lua_path = findScript(parts[0] + ".lua"); Plugin *plug = plug_mgr->getPluginByCommand(parts[0]); if (builtin) { @@ -976,7 +981,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s { con << " is a command implemented by the plugin " << plug->getName() << std::endl; } - else if (lua_path.size()) + else if (!lua_path.empty()) { con << " is a Lua script: " << lua_path << std::endl; } @@ -1123,7 +1128,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s { if(parts.size() == 1) { - loadScriptFile(con, parts[0], false); + loadScriptFile(con, std::filesystem::canonical(std::filesystem::path{parts[0]}), false); } else { @@ -1286,8 +1291,8 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s else if (res == CR_NOT_IMPLEMENTED) { std::string completed; - std::string filename = findScript(first + ".lua"); - bool lua = filename != ""; + std::filesystem::path filename = findScript(first + ".lua"); + bool lua = !filename.empty(); if ( !lua ) { filename = findScript(first + ".rb"); } @@ -1330,17 +1335,17 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s return CR_OK; } -bool Core::loadScriptFile(color_ostream &out, std::string fname, bool silent) +bool Core::loadScriptFile(color_ostream &out, std::filesystem::path fname, bool silent) { if(!silent) { INFO(script,out) << "Running script: " << fname << std::endl; std::cerr << "Running script: " << fname << std::endl; } - std::ifstream script(fname.c_str()); + std::ifstream script(fname); if ( !script.good() ) { if(!silent) - out.printerr("Error loading script: %s\n", fname.c_str()); + out.printerr("Error loading script: %s\n", fname.string().c_str()); return false; } std::string command; @@ -1379,11 +1384,11 @@ static void run_dfhack_init(color_ostream &out, Core *core) } // load baseline defaults - core->loadScriptFile(out, CONFIG_PATH + "init/default.dfhack.init", false); + core->loadScriptFile(out, CONFIG_PATH / "init" / "default.dfhack.init", false); // load user overrides std::vector prefixes(1, "dfhack"); - loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init"); + loadScriptFiles(core, out, prefixes, CONFIG_PATH / "init"); // show the terminal if requested auto L = DFHack::Core::getInstance().getLuaState(); @@ -1407,7 +1412,7 @@ void fInitthread(void * iodata) // A thread function... for the interactive console. void fIOthread(void * iodata) { - static const std::string HISTORY_FILE = CONFIG_PATH + "dfhack.history"; + static const std::filesystem::path HISTORY_FILE = CONFIG_PATH / "dfhack.history"; IODATA * iod = ((IODATA*) iodata); Core * core = iod->core; @@ -1455,7 +1460,7 @@ void fIOthread(void * iodata) { // a proper, non-empty command was entered main_history.add(command); - main_history.save(HISTORY_FILE.c_str()); + main_history.save(HISTORY_FILE); } auto rv = core->runCommand(con, command); @@ -1534,13 +1539,9 @@ void Core::fatal (std::string output, const char * title) } } -std::string Core::getHackPath() +std::filesystem::path Core::getHackPath() { -#ifdef LINUX_BUILD - return p->getPath() + "/hack/"; -#else - return p->getPath() + "\\hack\\"; -#endif + return p->getPath() / "hack"; } df::viewscreen * Core::getTopViewscreen() { @@ -1781,8 +1782,8 @@ bool Core::InitSimulationThread() con.printerr("Failed to create config directory: '%s'\n", CONFIG_PATH.c_str()); // copy over default config files if necessary - std::map config_files; - std::map default_config_files; + std::map config_files; + std::map default_config_files; if (Filesystem::listdir_recursive(CONFIG_PATH, config_files, 10, false) != 0) con.printerr("Failed to list directory: '%s'\n", CONFIG_PATH.c_str()); else if (Filesystem::listdir_recursive(CONFIG_DEFAULTS_PATH, default_config_files, 10, false) != 0) @@ -1794,7 +1795,7 @@ bool Core::InitSimulationThread() // skip over files if (!entry.second) continue; - std::string dirname = CONFIG_PATH + entry.first; + std::filesystem::path dirname = CONFIG_PATH / entry.first; if (!Filesystem::mkdir_recursive(dirname)) con.printerr("Failed to create config directory: '%s'\n", dirname.c_str()); } @@ -1804,12 +1805,12 @@ bool Core::InitSimulationThread() // skip over directories if (entry.second) continue; - std::string filename = entry.first; + std::filesystem::path filename = entry.first; if (!config_files.count(filename)) { - std::string src_file = CONFIG_DEFAULTS_PATH + filename; + std::filesystem::path src_file = CONFIG_DEFAULTS_PATH / filename; if (!Filesystem::isfile(src_file)) continue; - std::string dest_file = CONFIG_PATH + filename; + std::filesystem::path dest_file = CONFIG_PATH / filename; std::ifstream src(src_file, std::ios::binary); std::ofstream dest(dest_file, std::ios::binary); if (!src.good() || !dest.good()) { @@ -2185,42 +2186,30 @@ void Core::onUpdate(color_ostream &out) perf_counters.incCounter(perf_counters.update_lua_ms, step_start_ms); } -void getFilesWithPrefixAndSuffix(const std::string& folder, const std::string& prefix, const std::string& suffix, std::vector& result) { - std::vector files; +void getFilesWithPrefixAndSuffix(const std::filesystem::path& folder, const std::string& prefix, const std::string& suffix, std::vector& result) { + std::vector files; DFHack::Filesystem::listdir(folder, files); - for ( size_t a = 0; a < files.size(); a++ ) { - if ( prefix.length() > files[a].length() ) - continue; - if ( suffix.length() > files[a].length() ) - continue; - if ( files[a].compare(0, prefix.length(), prefix) != 0 ) - continue; - if ( files[a].compare(files[a].length()-suffix.length(), suffix.length(), suffix) != 0 ) - continue; - result.push_back(files[a]); + for ( auto f : files) { + if (f.stem().string().starts_with(prefix) && f.extension() == suffix) + result.push_back(f); } return; } -size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector& prefix, const std::string& folder) { +size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector& prefix, const std::filesystem::path& folder) { static const std::string suffix = ".init"; - std::vector scriptFiles; + std::vector scriptFiles; for ( size_t a = 0; a < prefix.size(); a++ ) { getFilesWithPrefixAndSuffix(folder, prefix[a], ".init", scriptFiles); } std::sort(scriptFiles.begin(), scriptFiles.end(), - [&](const std::string &a, const std::string &b) { - std::string a_base = a.substr(0, a.size() - suffix.size()); - std::string b_base = b.substr(0, b.size() - suffix.size()); - return a_base < b_base; + [&](const std::filesystem::path &a, const std::filesystem::path &b) { + return a < b; }); size_t result = 0; for ( size_t a = 0; a < scriptFiles.size(); a++ ) { result++; - std::string path = ""; - if (folder != ".") - path = folder + "/"; - core->loadScriptFile(out, path + scriptFiles[a], false); + core->loadScriptFile(out, folder / scriptFiles[a], false); } return result; } @@ -2272,16 +2261,16 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve if (!df::global::world) return; - std::string rawFolder = !isWorldLoaded() ? "" : "save/" + World::ReadWorldFolder() + "/init"; + std::filesystem::path rawFolder = !isWorldLoaded() ? std::filesystem::path{} : std::filesystem::path{} / "save" / World::ReadWorldFolder() / "init"; auto i = table.find(event); if ( i != table.end() ) { const std::vector& set = i->second; // load baseline defaults - this->loadScriptFile(out, CONFIG_PATH + "init/default." + set[0] + ".init", false); + this->loadScriptFile(out, CONFIG_PATH / "init" / ("default." + set[0] + ".init"), false); - loadScriptFiles(this, out, set, CONFIG_PATH + "init"); + loadScriptFiles(this, out, set, CONFIG_PATH / "init"); loadScriptFiles(this, out, set, rawFolder); } @@ -2295,7 +2284,7 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve } else if (it->save_specific && isWorldLoaded()) { - loadScriptFile(out, rawFolder + it->path, false); + loadScriptFile(out, rawFolder / it->path, false); } } } @@ -2366,7 +2355,7 @@ void Core::onStateChange(color_ostream &out, state_change_event event) strftime(timebuf, sizeof(timebuf), "[%Y-%m-%dT%H:%M:%S%z] ", timeinfo); evtlog << timebuf; evtlog << "DFHack " << Version::git_description() << " on " << ostype << "; "; - evtlog << "cwd md5: " << md5w.getHashFromString(getHackPath()).substr(0, 10) << "; "; + evtlog << "cwd md5: " << md5w.getHashFromString(getHackPath().string().c_str()).substr(0, 10) << "; "; evtlog << "save: " << world->cur_savegame.save_dir << "; "; evtlog << sc_event_name(event) << "; "; if (gametype) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 637df32211..d2162a33d1 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -115,6 +115,7 @@ distribution. #include #include #include +#include namespace DFHack { DBG_DECLARE(core, luaapi, DebugCategory::LINFO); @@ -1351,8 +1352,8 @@ static string getArchitectureName() static string getDFVersion() { return Core::getInstance().vinfo->getVersion(); } static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); } -static string getDFPath() { return Core::getInstance().p->getPath(); } -static string getHackPath() { return Core::getInstance().getHackPath(); } +static std::filesystem::path getDFPath() { return Core::getInstance().p->getPath(); } +static std::filesystem::path getHackPath() { return Core::getInstance().getHackPath(); } static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); } static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); } @@ -3153,8 +3154,6 @@ static const LuaWrapper::FunctionReg dfhack_filesystem_module[] = { WRAPM(Filesystem, exists), WRAPM(Filesystem, isfile), WRAPM(Filesystem, isdir), - WRAPM(Filesystem, atime), - WRAPM(Filesystem, ctime), WRAPM(Filesystem, mtime), {NULL, NULL} }; @@ -3163,7 +3162,7 @@ static int filesystem_listdir(lua_State *L) { luaL_checktype(L,1,LUA_TSTRING); string dir=lua_tostring(L,1); - vector files; + vector files; int err = DFHack::Filesystem::listdir(dir, files); if (err) { @@ -3176,7 +3175,7 @@ static int filesystem_listdir(lua_State *L) for(size_t i=0;i= 3 && !lua_isnil(L, 3)) include_prefix = lua_toboolean(L, 3); - std::map files; + std::map files; int err = DFHack::Filesystem::listdir_recursive(dir, files, depth, include_prefix); if (err != 0 && err != -1) { lua_pushnil(L); @@ -3207,7 +3206,7 @@ static int filesystem_listdir_recursive(lua_State *L) lua_pushinteger(L, i++); lua_newtable(L); lua_pushstring(L, "path"); - lua_pushstring(L, (it->first).c_str()); + lua_pushstring(L, (it->first).string().c_str()); lua_settable(L, -3); lua_pushstring(L, "isdir"); lua_pushboolean(L, it->second); @@ -3947,12 +3946,12 @@ static int internal_getScriptPaths(lua_State *L) { int i = 1; lua_newtable(L); - vector paths; + vector paths; Core::getInstance().getScriptPaths(&paths); for (auto it = paths.begin(); it != paths.end(); ++it) { lua_pushinteger(L, i++); - lua_pushstring(L, it->c_str()); + lua_pushstring(L, it->string().c_str()); lua_settable(L, -3); } return 1; @@ -3961,9 +3960,9 @@ static int internal_getScriptPaths(lua_State *L) static int internal_findScript(lua_State *L) { const char *name = luaL_checkstring(L, 1); - string path = Core::getInstance().findScript(name); - if (path.size()) - lua_pushstring(L, path.c_str()); + std::filesystem::path path = Core::getInstance().findScript(name); + if (!path.empty()) + lua_pushstring(L, path.string().c_str()); else lua_pushnil(L); return 1; diff --git a/library/PlugLoad.cpp b/library/PlugLoad.cpp index 059e6aef95..1cafc791f5 100644 --- a/library/PlugLoad.cpp +++ b/library/PlugLoad.cpp @@ -18,7 +18,7 @@ #define global_search_handle() GetModuleHandle(nullptr) #define get_function_address(plugin, function) GetProcAddress((HMODULE)plugin, function) #define clear_error() -#define load_library(fn) LoadLibrary(fn) +#define load_library(fn) LoadLibraryW(fn.c_str()) #define close_library(handle) (!(FreeLibrary((HMODULE)handle))) #else #include @@ -33,7 +33,7 @@ #define global_search_handle() (RTLD_DEFAULT) #define get_function_address(plugin, function) dlsym((void*)plugin, function) #define clear_error() dlerror() -#define load_library(fn) dlopen(fn, RTLD_NOW | RTLD_LOCAL); +#define load_library(fn) dlopen(fn.c_str(), RTLD_NOW | RTLD_LOCAL); #define close_library(handle) dlclose((void*)handle) #endif @@ -71,7 +71,7 @@ namespace DFHack } } - DFLibrary * OpenPlugin (const char * filename) + DFLibrary * OpenPlugin (std::filesystem::path filename) { clear_error(); DFLibrary* ret = (DFLibrary*)load_library(filename); diff --git a/library/PluginManager.cpp b/library/PluginManager.cpp index 458c0377c2..98a9eaeec4 100644 --- a/library/PluginManager.cpp +++ b/library/PluginManager.cpp @@ -48,7 +48,8 @@ using namespace DFHack; #include #include #include -using namespace std; + +using std::string; #include @@ -60,14 +61,14 @@ using namespace std; static const string plugin_suffix = ".plug.dll"; #endif -static string getPluginPath() +static std::filesystem::path getPluginPath() { - return Core::getInstance().getHackPath() + "plugins/"; + return Core::getInstance().getHackPath() / "plugins"; } -static string getPluginPath (std::string name) +static std::filesystem::path getPluginPath (std::string name) { - return getPluginPath() + name + plugin_suffix; + return getPluginPath() / (name + plugin_suffix); } struct Plugin::RefLock @@ -175,7 +176,7 @@ struct Plugin::LuaEvent : public Lua::Event::Owner { } }; -Plugin::Plugin(Core * core, const std::string & path, +Plugin::Plugin(Core * core, const std::filesystem::path& path, const std::string &name, PluginManager * pm) :path(path), name(name), @@ -246,7 +247,7 @@ bool Plugin::load(color_ostream &con) CoreSuspender suspend; // open the library, etc fprintf(stderr, "loading plugin %s\n", name.c_str()); - DFLibrary * plug = OpenPlugin(path.c_str()); + DFLibrary * plug = OpenPlugin(path); if(!plug) { RefAutolock lock(access); @@ -311,8 +312,8 @@ bool Plugin::load(color_ostream &con) { std::string msg = stl_sprintf("Warning: Plugin %s compiled for DFHack %s, running DFHack %s\n", *plug_name, plug_git_desc, dfhack_git_desc); - con << msg << flush; - cerr << msg << flush; + con << msg << std::flush; + std::cerr << msg << std::flush; } } else @@ -895,7 +896,7 @@ bool PluginManager::addPlugin(string name) Core::printerr("Plugin already exists: %s\n", name.c_str()); return false; } - string path = getPluginPath(name); + std::filesystem::path path = getPluginPath(name); if (!Filesystem::isfile(path)) { Core::printerr("Plugin does not exist: %s\n", name.c_str()); @@ -906,16 +907,17 @@ bool PluginManager::addPlugin(string name) return true; } -vector PluginManager::listPlugins() +std::vector PluginManager::listPlugins() { - vector results; - vector files; + std::vector results; + std::vector files; Filesystem::listdir(getPluginPath(), files); for (auto file = files.begin(); file != files.end(); ++file) { - if (hasEnding(*file, plugin_suffix)) + string fname = file->filename().string(); + if (hasEnding(file->filename().string(), plugin_suffix)) { - string shortname = file->substr(0, file->find(plugin_suffix)); + string shortname = fname.substr(0, fname.find(plugin_suffix)); results.push_back(shortname); } } @@ -924,7 +926,7 @@ vector PluginManager::listPlugins() void PluginManager::refresh() { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; auto files = listPlugins(); for (auto f = files.begin(); f != files.end(); ++f) { @@ -935,7 +937,7 @@ void PluginManager::refresh() bool PluginManager::load (const string &name) { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; if (!(*this)[name] && !addPlugin(name)) return false; Plugin *p = (*this)[name]; @@ -949,7 +951,7 @@ bool PluginManager::load (const string &name) bool PluginManager::loadAll() { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; auto files = listPlugins(); bool ok = true; // load all plugins in hack/plugins @@ -963,7 +965,7 @@ bool PluginManager::loadAll() bool PluginManager::unload (const string &name) { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; if (!(*this)[name]) { Core::printerr("Plugin does not exist: %s\n", name.c_str()); @@ -974,7 +976,7 @@ bool PluginManager::unload (const string &name) bool PluginManager::unloadAll() { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; bool ok = true; // only try to unload plugins that are in all_plugins for (auto it = begin(); it != end(); ++it) @@ -989,7 +991,7 @@ bool PluginManager::reload (const string &name) { // equivalent to "unload(name); load(name);" if plugin is recognized, // "load(name);" otherwise - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; if (!(*this)[name]) return load(name); if (!unload(name)) @@ -999,7 +1001,7 @@ bool PluginManager::reload (const string &name) bool PluginManager::reloadAll() { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; bool ok = true; if (!unloadAll()) ok = false; @@ -1010,8 +1012,8 @@ bool PluginManager::reloadAll() Plugin *PluginManager::getPluginByCommand(const std::string &command) { - lock_guard lock{*cmdlist_mutex}; - map ::iterator iter = command_map.find(command); + std::lock_guard lock{*cmdlist_mutex}; + std::map ::iterator iter = command_map.find(command); if (iter != command_map.end()) return iter->second; else @@ -1059,8 +1061,8 @@ void PluginManager::OnStateChange(color_ostream &out, state_change_event event) void PluginManager::registerCommands( Plugin * p ) { - lock_guard lock{*cmdlist_mutex}; - vector & cmds = p->commands; + std::lock_guard lock{*cmdlist_mutex}; + std::vector & cmds = p->commands; for (size_t i = 0; i < cmds.size();i++) { std::string name = cmds[i].name; @@ -1076,8 +1078,8 @@ void PluginManager::registerCommands( Plugin * p ) void PluginManager::unregisterCommands( Plugin * p ) { - lock_guard lock{*cmdlist_mutex}; - vector & cmds = p->commands; + std::lock_guard lock{*cmdlist_mutex}; + std::vector & cmds = p->commands; for(size_t i = 0; i < cmds.size();i++) { command_map.erase(cmds[i].name); @@ -1126,7 +1128,7 @@ void PluginManager::doLoadSiteData(color_ostream &out) Plugin *PluginManager::operator[] (std::string name) { - lock_guard lock{*plugin_mutex}; + std::lock_guard lock{*plugin_mutex}; if (all_plugins.find(name) == all_plugins.end()) { if (Filesystem::isfile(getPluginPath(name))) diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index a3fa9f2d67..ce64cc113b 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -195,7 +195,7 @@ uint32_t Process::getTickCount() return (tp.tv_sec * 1000) + (tp.tv_usec / 1000); } -string Process::getPath() +std::filesystem::path Process::getPath() { return Filesystem::get_initial_cwd(); } diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index 79bbea8002..fe8c5d591a 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -29,6 +29,7 @@ distribution. #include #include #include +#include #include "Error.h" #include "Internal.h" @@ -53,7 +54,6 @@ using std::vector; using std::endl; using std::cerr; - namespace DFHack { class PlatformSpecific @@ -382,7 +382,7 @@ uint32_t Process::getTickCount() return GetTickCount(); } -string Process::getPath() +std::filesystem::path Process::getPath() { HMODULE hmod; DWORD junk; diff --git a/library/Types.cpp b/library/Types.cpp index ffed86eb59..1dab657c1c 100644 --- a/library/Types.cpp +++ b/library/Types.cpp @@ -33,24 +33,16 @@ distribution. #include "df/general_ref.h" #include "df/specific_ref.h" -#ifndef LINUX_BUILD - #include - #include "wdirent.h" -#else - #include - #include - #include - #include -#endif - #include #include +#include #include #include +#include -int DFHack::getdir(std::string dir, std::vector &files) +int DFHack::getdir(std::filesystem::path dir, std::vector &files) { return DFHack::Filesystem::listdir(dir, files); } diff --git a/library/include/Console.h b/library/include/Console.h index a4ca8c5452..4397c75954 100644 --- a/library/include/Console.h +++ b/library/include/Console.h @@ -33,6 +33,7 @@ distribution. #include #include #include +#include namespace DFHack { @@ -43,7 +44,7 @@ namespace DFHack { this->capacity = capacity; } - bool load (const char * filename) + bool load (std::filesystem::path filename) { std::string reader; std::ifstream infile(filename); @@ -58,7 +59,7 @@ namespace DFHack } return true; } - bool save (const char * filename) + bool save (std::filesystem::path filename) { if (!history.size()) return true; diff --git a/library/include/Core.h b/library/include/Core.h index 556e5e1b03..6794a6b28f 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -175,13 +175,13 @@ namespace DFHack command_result runCommand(color_ostream &out, const std::string &command, std::vector ¶meters, bool no_autocomplete = false); command_result runCommand(color_ostream &out, const std::string &command); - bool loadScriptFile(color_ostream &out, std::string fname, bool silent = false); + bool loadScriptFile(color_ostream &out, std::filesystem::path fname, bool silent = false); bool addScriptPath(std::string path, bool search_before = false); bool setModScriptPaths(const std::vector &mod_script_paths); bool removeScriptPath(std::string path); - std::string findScript(std::string name); - void getScriptPaths(std::vector *dest); + std::filesystem::path findScript(std::string name); + void getScriptPaths(std::vector *dest); bool getSuppressDuplicateKeyboardEvents(); void setSuppressDuplicateKeyboardEvents(bool suppress); @@ -201,7 +201,7 @@ namespace DFHack std::map> ListAliases(); std::string GetAliasCommand(const std::string &name, bool ignore_params = false); - std::string getHackPath(); + std::filesystem::path getHackPath(); bool isWorldLoaded() { return (last_world_data_ptr != NULL); } bool isMapLoaded() { return (last_local_map_ptr != NULL && last_world_data_ptr != NULL); } diff --git a/library/include/MemAccess.h b/library/include/MemAccess.h index bcbab75bd3..95f7e256d1 100644 --- a/library/include/MemAccess.h +++ b/library/include/MemAccess.h @@ -33,6 +33,7 @@ distribution. #include #include #include +#include #include "VersionInfo.h" @@ -262,7 +263,7 @@ namespace DFHack /// get the DF Process ID int getPID(); /// get the DF Process FilePath - std::string getPath(); + std::filesystem::path getPath(); /// Adjust between in-memory and in-file image offset int adjustOffset(int offset, bool to_file = false); diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index 3749ff9548..50b9b0447d 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -64,7 +64,7 @@ namespace DFHack // DFLibrary* that can be used to resolve global names extern DFLibrary* GLOBAL_NAMES; // Open a plugin library - DFHACK_EXPORT DFLibrary * OpenPlugin (const char * filename); + DFHACK_EXPORT DFLibrary * OpenPlugin (std::filesystem::path filename); // find a symbol inside plugin DFHACK_EXPORT void * LookupPlugin (DFLibrary * plugin ,const char * function); // Close a plugin library. returns true on success, false on failure @@ -143,7 +143,7 @@ namespace DFHack struct RefAutoinc; friend class PluginManager; friend class RPCService; - Plugin(DFHack::Core* core, const std::string& filepath, + Plugin(DFHack::Core* core, const std::filesystem::path& filepath, const std::string &plug_name, PluginManager * pm); ~Plugin(); command_result on_update(color_ostream &out); @@ -202,7 +202,7 @@ namespace DFHack RefLock * access; std::vector commands; std::vector services; - std::string path; + std::filesystem::path path; std::string name; DFLibrary * plugin_lib; PluginManager * parent; diff --git a/library/include/Types.h b/library/include/Types.h index 53b6aee18a..84408ecf2a 100644 --- a/library/include/Types.h +++ b/library/include/Types.h @@ -26,6 +26,8 @@ distribution. #pragma once #include +#include +#include #include "Export.h" @@ -118,7 +120,7 @@ namespace DFHack return rect.second - rect.first + df::coord2d(1,1); } - DFHACK_EXPORT int getdir(std::string dir, std::vector &files); + DFHACK_EXPORT int getdir(std::filesystem::path dir, std::vector &files); DFHACK_EXPORT bool hasEnding (std::string const &fullString, std::string const &ending); DFHACK_EXPORT df::general_ref *findRef(std::vector &vec, df::general_ref_type type); diff --git a/library/include/modules/Filesystem.h b/library/include/modules/Filesystem.h index 8e7bab9b20..8c376a7a01 100644 --- a/library/include/modules/Filesystem.h +++ b/library/include/modules/Filesystem.h @@ -50,123 +50,29 @@ SOFTWARE. #include #include -#ifndef _WIN32 - #ifndef _AIX - #define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */ - #else - #define _LARGE_FILES 1 /* AIX */ - #endif -#endif +#include -#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 - #include - #define NOMINMAX - #include - #include - #include - #ifdef __BORLANDC__ - #include - #else - #include - #endif - #include - #include "wdirent.h" -#else - #include - #include - #include - #include - #include -#endif - -#ifdef _WIN32 - #ifdef __BORLANDC__ - #define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m)) - #define STAT_STRUCT struct stati64 - #else - #define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m)) - #define STAT_STRUCT struct _stati64 - #endif - #define STAT_FUNC _stati64 - #define LSTAT_FUNC STAT_FUNC -#else - #define _O_TEXT 0 - #define _O_BINARY 0 - #define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0) - #define STAT_STRUCT struct stat - #define STAT_FUNC stat - #define LSTAT_FUNC lstat -#endif - -#ifdef _WIN32 - #ifndef S_ISDIR - #define S_ISDIR(mode) (mode&_S_IFDIR) - #endif - #ifndef S_ISREG - #define S_ISREG(mode) (mode&_S_IFREG) - #endif - #ifndef S_ISLNK - #define S_ISLNK(mode) (0) - #endif - #ifndef S_ISSOCK - #define S_ISSOCK(mode) (0) - #endif - #ifndef S_ISCHR - #define S_ISCHR(mode) (mode&_S_IFCHR) - #endif - #ifndef S_ISBLK - #define S_ISBLK(mode) (0) - #endif -#endif - -enum _filetype { - FILETYPE_NONE = -2, - FILETYPE_UNKNOWN = -1, - FILETYPE_FILE = 1, - FILETYPE_DIRECTORY, - FILETYPE_LINK, - FILETYPE_SOCKET, - FILETYPE_NAMEDPIPE, - FILETYPE_CHAR_DEVICE, - FILETYPE_BLOCK_DEVICE -}; namespace DFHack { namespace Filesystem { DFHACK_EXPORT void init (); - DFHACK_EXPORT bool chdir (std::string path); - DFHACK_EXPORT std::string getcwd (); + DFHACK_EXPORT bool chdir (std::filesystem::path path); + DFHACK_EXPORT std::filesystem::path getcwd (); DFHACK_EXPORT bool restore_cwd (); - DFHACK_EXPORT std::string get_initial_cwd (); - DFHACK_EXPORT bool mkdir (std::string path); + DFHACK_EXPORT std::filesystem::path get_initial_cwd (); + DFHACK_EXPORT bool mkdir (std::filesystem::path path); // returns true on success or if directory already exists - DFHACK_EXPORT bool mkdir_recursive (std::string path); - DFHACK_EXPORT bool rmdir (std::string path); - DFHACK_EXPORT bool stat (std::string path, STAT_STRUCT &info); - DFHACK_EXPORT bool exists (std::string path); - DFHACK_EXPORT _filetype filetype (std::string path); - DFHACK_EXPORT bool isfile (std::string path); - DFHACK_EXPORT bool isdir (std::string path); - DFHACK_EXPORT int64_t atime (std::string path); - DFHACK_EXPORT int64_t ctime (std::string path); - DFHACK_EXPORT int64_t mtime (std::string path); - DFHACK_EXPORT int listdir (std::string dir, std::vector &files); + DFHACK_EXPORT bool mkdir_recursive (std::filesystem::path path); + DFHACK_EXPORT bool rmdir (std::filesystem::path path); + DFHACK_EXPORT bool stat (std::filesystem::path path, std::filesystem::file_status &info); + DFHACK_EXPORT bool exists (std::filesystem::path path); + DFHACK_EXPORT bool isfile (std::filesystem::path path); + DFHACK_EXPORT bool isdir (std::filesystem::path path); + DFHACK_EXPORT std::time_t mtime (std::filesystem::path path); + DFHACK_EXPORT int listdir (std::filesystem::path dir, std::vector &files); // set include_prefix to false to prevent dir from being prepended to // paths returned in files - DFHACK_EXPORT int listdir_recursive (std::string dir, std::map &files, + DFHACK_EXPORT int listdir_recursive (std::filesystem::path dir, std::map &files, int depth = 10, bool include_prefix = true); } } diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index 2c275ceba8..8b316d34c8 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -47,13 +47,15 @@ SOFTWARE. #include #include +#include +#include #include "modules/Filesystem.h" using namespace DFHack; static bool initialized = false; -static std::string initial_cwd; +static std::filesystem::path initial_cwd; void Filesystem::init () { @@ -64,24 +66,23 @@ void Filesystem::init () } } -bool Filesystem::chdir (std::string path) +bool Filesystem::chdir (std::filesystem::path path) { Filesystem::init(); - return ::chdir(path.c_str()) == 0; + try + { + std::filesystem::current_path(path); + return true; + } + catch (std::filesystem::filesystem_error&) + { + return false; + } } -std::string Filesystem::getcwd () +std::filesystem::path Filesystem::getcwd () { - char *path; - char buf[FILENAME_MAX]; - std::string result = ""; -#ifdef _WIN32 - if ((path = ::_getcwd(buf, FILENAME_MAX)) != NULL) -#else - if ((path = ::getcwd(buf, FILENAME_MAX)) != NULL) -#endif - result = buf; - return result; + return std::filesystem::current_path(); } bool Filesystem::restore_cwd () @@ -89,196 +90,124 @@ bool Filesystem::restore_cwd () return Filesystem::chdir(initial_cwd); } -std::string Filesystem::get_initial_cwd () +std::filesystem::path Filesystem::get_initial_cwd () { Filesystem::init(); return initial_cwd; } -bool Filesystem::mkdir (std::string path) +bool Filesystem::mkdir (std::filesystem::path path) { - int fail; -#ifdef _WIN32 - fail = ::_mkdir(path.c_str()); -#else - fail = ::mkdir(path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | - S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH); -#endif - return fail == 0; -} - -static bool mkdir_recursive_impl (std::string path) -{ - size_t last_slash = path.find_last_of("/"); - if (last_slash != std::string::npos) + try { - std::string parent_path = path.substr(0, last_slash); - bool parent_exists = mkdir_recursive_impl(parent_path); - if (!parent_exists) - { - return false; - } + std::filesystem::create_directory(path); + return true; } - return (Filesystem::mkdir(path) || errno == EEXIST) && Filesystem::isdir(path); -} - -bool Filesystem::mkdir_recursive (std::string path) -{ -#ifdef _WIN32 - // normalize to forward slashes - std::replace(path.begin(), path.end(), '\\', '/'); -#endif - - if (path.size() > FILENAME_MAX) + catch (std::filesystem::filesystem_error&) { - // path too long return false; } - - return mkdir_recursive_impl(path); } -bool Filesystem::rmdir (std::string path) +bool Filesystem::mkdir_recursive (std::filesystem::path path) { - int fail; -#ifdef _WIN32 - fail = ::_rmdir(path.c_str()); -#else - fail = ::rmdir(path.c_str()); -#endif - return fail == 0; -} - -#ifdef _WIN32 -_filetype mode2type (unsigned short mode) { -#else -_filetype mode2type (mode_t mode) { -#endif - if (S_ISREG(mode)) - return FILETYPE_FILE; - else if (S_ISDIR(mode)) - return FILETYPE_DIRECTORY; - else if (S_ISLNK(mode)) - return FILETYPE_LINK; - else if (S_ISSOCK(mode)) - return FILETYPE_SOCKET; - else if (S_ISCHR(mode)) - return FILETYPE_CHAR_DEVICE; - else if (S_ISBLK(mode)) - return FILETYPE_BLOCK_DEVICE; - else - return FILETYPE_UNKNOWN; + try + { + std::filesystem::create_directories(path); + return true; + } + catch (std::filesystem::filesystem_error&) + { + return false; + } } -bool Filesystem::stat (std::string path, STAT_STRUCT &info) +bool Filesystem::rmdir (std::filesystem::path path) { - return (STAT_FUNC(path.c_str(), &info)) == 0; + try + { + std::filesystem::remove(path); + return true; + } + catch (std::filesystem::filesystem_error&) + { + return false; + } } -bool Filesystem::exists (std::string path) +bool Filesystem::stat (std::filesystem::path path, std::filesystem::file_status &info) { - STAT_STRUCT info; - return Filesystem::stat(path, info); + try + { + info = std::filesystem::status(path); + return true; + } + catch (std::filesystem::filesystem_error&) + { + return false; + } } -_filetype Filesystem::filetype (std::string path) +bool Filesystem::exists (std::filesystem::path path) { - STAT_STRUCT info; - if (!Filesystem::stat(path, info)) - return FILETYPE_NONE; - return mode2type(info.st_mode); + return std::filesystem::exists(path); } -bool Filesystem::isfile (std::string path) +bool Filesystem::isfile(std::filesystem::path path) { - return Filesystem::exists(path) && Filesystem::filetype(path) == FILETYPE_FILE; + return std::filesystem::exists(path) && std::filesystem::is_regular_file(path); } -bool Filesystem::isdir (std::string path) +bool Filesystem::isdir (std::filesystem::path path) { - return Filesystem::exists(path) && Filesystem::filetype(path) == FILETYPE_DIRECTORY; -} - -#define DEFINE_STAT_TIME_WRAPPER(attr) \ -int64_t Filesystem::attr (std::string path) \ -{ \ - STAT_STRUCT info; \ - if (!Filesystem::stat(path, info)) \ - return -1; \ - return (int64_t)info.st_##attr; \ + return std::filesystem::exists(path) && std::filesystem::is_directory(path); } -DEFINE_STAT_TIME_WRAPPER(atime) -DEFINE_STAT_TIME_WRAPPER(ctime) -DEFINE_STAT_TIME_WRAPPER(mtime) - -#undef DEFINE_STAT_TIME_WRAPPER - -int Filesystem::listdir (std::string dir, std::vector &files) +std::time_t Filesystem::mtime (std::filesystem::path path) { - DIR *dp; - struct dirent *dirp; - if((dp = opendir(dir.c_str())) == NULL) + try { - return errno; + auto ftime = std::filesystem::last_write_time(path); + return ftime.time_since_epoch().count(); } - while ((dirp = readdir(dp)) != NULL) { - files.push_back(std::string(dirp->d_name)); + catch (std::filesystem::filesystem_error&) + { + return 0; } - closedir(dp); - return 0; } -// prefix is the top-level dir where we started recursing -// path is the relative path under the prefix; must be empty or end in a '/' -// files is the output list of files and directories (bool == true for dir) -// depth is the remaining dir depth to recurse into. function returns -1 if -// we haven't finished recursing when we run out of depth. -// include_prefix controls whether the directory where we started recursing is -// included in the filenames returned in files. -static int listdir_recursive_impl (std::string prefix, std::string path, - std::map &files, int depth, bool include_prefix) +int Filesystem::listdir (std::filesystem::path dir, std::vector &files) { - if (depth < 0) - return -1; - std::string prefixed_path = prefix + "/" + path; - std::vector curdir_files; - int err = Filesystem::listdir(prefixed_path, curdir_files); - if (err) - return err; - bool out_of_depth = false; - for (auto file = curdir_files.begin(); file != curdir_files.end(); ++file) - { - if (*file == "." || *file == "..") - continue; - std::string prefixed_file = prefixed_path + *file; - std::string path_file = path + *file; - if (Filesystem::isdir(prefixed_file)) - { - files.insert(std::pair(include_prefix ? prefixed_file : path_file, true)); - - if (depth == 0) - { - out_of_depth = true; - continue; - } - - err = listdir_recursive_impl(prefix, path_file + "/", files, depth - 1, include_prefix); - if (err) - return err; - } - else + try { + for (auto const& dirent : std::filesystem::directory_iterator(dir)) { - files.insert(std::pair(include_prefix ? prefixed_file : path_file, false)); + files.push_back(dirent.path().filename()); } + return 0; + } + catch (std::filesystem::filesystem_error&) + { + return 1; } - return out_of_depth ? -1 : 0; } -int Filesystem::listdir_recursive (std::string dir, std::map &files, +int Filesystem::listdir_recursive (std::filesystem::path dir, std::map &files, int depth /* = 10 */, bool include_prefix /* = true */) { - if (dir.size() && dir[dir.size()-1] == '/') - dir.resize(dir.size()-1); - return listdir_recursive_impl(dir, "", files, depth, include_prefix); + try { + for (auto i = std::filesystem::recursive_directory_iterator(dir); + i != std::filesystem::recursive_directory_iterator(); + ++i) + { + if (i->is_directory() && i.depth() >= depth) + i.disable_recursion_pending(); + auto dirent = include_prefix ? *i : std::filesystem::relative(dir, *i); + files.emplace(dirent, i->is_directory()); + } + return 0; + } + catch (std::filesystem::filesystem_error&) + { + return 1; + } } diff --git a/library/modules/Persistence.cpp b/library/modules/Persistence.cpp index 0a6f1c3772..9e1dd4d018 100644 --- a/library/modules/Persistence.cpp +++ b/library/modules/Persistence.cpp @@ -183,12 +183,12 @@ static std::string filterSaveFileName(std::string s) { return s; } -static std::string getSavePath(const std::string &world) { - return "save/" + world; +static std::filesystem::path getSavePath(const std::string &world) { + return std::filesystem::path{} / "save" / world; } -static std::string getSaveFilePath(const std::string &world, const std::string &name) { - return getSavePath(world) + "/dfhack-" + filterSaveFileName(name) + ".dat"; +static std::filesystem::path getSaveFilePath(const std::string &world, const std::string &name) { + return getSavePath(world) / ("dfhack-" + filterSaveFileName(name) + ".dat"); } struct LastLoadSaveTickCountUpdater { @@ -266,7 +266,7 @@ static void add_entry(int entity_id, std::shared_ptr ent add_entry(store[entity_id], entry); } -static bool load_file(const std::string & path, int entity_id) { +static bool load_file(const std::filesystem::path & path, int entity_id) { Json::Value json; try { std::ifstream file(path); @@ -298,8 +298,8 @@ void Persistence::Internal::load(color_ostream& out) { clear(out); std::string world_name = World::ReadWorldFolder(); - std::string save_path = getSavePath(world_name); - std::vector files; + std::filesystem::path save_path = getSavePath(world_name); + std::vector files; if (0 != Filesystem::listdir(save_path, files)) { DEBUG(persistence,out).print("not loading state; save directory doesn't exist: '%s'\n", save_path.c_str()); return; @@ -308,11 +308,11 @@ void Persistence::Internal::load(color_ostream& out) { bool found = false; for (auto & fname : files) { int entity_id = Persistence::WORLD_ENTITY_ID; - if (fname != "dfhack-world.dat" && !get_entity_id(fname, entity_id)) + if (fname != "dfhack-world.dat" && !get_entity_id(fname.string(), entity_id)) continue; found = true; - std::string path = save_path + "/" + fname; + std::filesystem::path path = save_path / fname; if (!load_file(path, entity_id)) out.printerr("Cannot load data from: '%s'\n", path.c_str()); } @@ -321,7 +321,7 @@ void Persistence::Internal::load(color_ostream& out) { return; // new file formats not found; attempt to load legacy file - const std::string legacy_fname = getSaveFilePath(world_name, "legacy-data"); + const std::filesystem::path legacy_fname = getSaveFilePath(world_name, "legacy-data"); if (Filesystem::exists(legacy_fname)) { int synthesized_entity_id = Persistence::WORLD_ENTITY_ID; if (World::IsSiteLoaded()) diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 49558c1b88..a2da1f0ae9 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -134,7 +134,7 @@ static command_result orders_command(color_ostream & out, std::vector files; + std::map files; if (0 < Filesystem::listdir_recursive(ORDERS_LIBRARY_DIR, files, 0, false)) { // if the library directory doesn't exist, just skip it return; @@ -145,15 +145,15 @@ static void list_library(color_ostream &out) { return; } - for (auto it : files) + for (auto& it : files) { if (it.second) continue; // skip directories - std::string name = it.first; - if (name.length() <= 5 || name.rfind(".json") != name.length() - 5) + std::filesystem::path name = it.first; + if (name.extension() != ".json") continue; // skip non-.json files - name.resize(name.length() - 5); - out << "library/" << name << std::endl; + auto sname = name.stem(); + out << "library/" << sname << std::endl; } } @@ -162,17 +162,17 @@ static command_result orders_list_command(color_ostream & out) // use listdir_recursive instead of listdir even though orders doesn't // support subdirs so we can identify and ignore subdirs with ".json" names. // also listdir_recursive will alphabetize the list for us. - std::map files; + std::map files; Filesystem::listdir_recursive(ORDERS_DIR, files, 0, false); - for (auto it : files) { + for (auto& it : files) { if (it.second) continue; // skip directories - std::string name = it.first; - if (name.length() <= 5 || name.rfind(".json") != name.length() - 5) + std::filesystem::path name = it.first; + if (name.extension() != ".json") continue; // skip non-.json files - name.resize(name.length() - 5); - out << name << std::endl; + auto sname = name.stem(); + out << sname << std::endl; } list_library(out); From e8274319e92c82c45a8d549b751ba8d30cfd2038 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 09:34:24 -0500 Subject: [PATCH 02/20] fix docs --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index ed65524207..ee2551a94e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ Template for new versions: ## Documentation ## API -- `Filesystem` module: rewritten to use C++ standard library components, for better portability +- ``Filesystem`` module: rewritten to use C++ standard library components, for better portability ## Lua From a17c0ca56bc4481e8e306aaa29a3d921872763a7 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 09:41:31 -0500 Subject: [PATCH 03/20] transform argument to printf really wish we could use `std::format` --- library/PlugLoad.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/PlugLoad.cpp b/library/PlugLoad.cpp index 1cafc791f5..ec72e36fb9 100644 --- a/library/PlugLoad.cpp +++ b/library/PlugLoad.cpp @@ -77,7 +77,7 @@ namespace DFHack DFLibrary* ret = (DFLibrary*)load_library(filename); if (!ret) { auto error = get_error(); - WARN(plugins).print("OpenPlugin on %s failed: %s\n", filename, error.c_str()); + WARN(plugins).print("OpenPlugin on %s failed: %s\n", filename.string().c_str(), error.c_str()); } return ret; } From 1945981b945046182e4a99e65fb3b2111471741d Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 10:12:23 -0500 Subject: [PATCH 04/20] add `canonicalize` method to `Filesystem` and use in tests instead of hacky regexp --- library/LuaApi.cpp | 1 + library/include/modules/Filesystem.h | 1 + library/modules/Filesystem.cpp | 6 ++++++ test/core.lua | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d2162a33d1..cc8c643b74 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -3155,6 +3155,7 @@ static const LuaWrapper::FunctionReg dfhack_filesystem_module[] = { WRAPM(Filesystem, isfile), WRAPM(Filesystem, isdir), WRAPM(Filesystem, mtime), + WRAPM(Filesystem, canonicalize), {NULL, NULL} }; diff --git a/library/include/modules/Filesystem.h b/library/include/modules/Filesystem.h index 8c376a7a01..d2b6f7a9b8 100644 --- a/library/include/modules/Filesystem.h +++ b/library/include/modules/Filesystem.h @@ -74,5 +74,6 @@ namespace DFHack { // paths returned in files DFHACK_EXPORT int listdir_recursive (std::filesystem::path dir, std::map &files, int depth = 10, bool include_prefix = true); + DFHACK_EXPORT std::filesystem::path canonicalize(std::filesystem::path p); } } diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index 8b316d34c8..9e81ba8d10 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -211,3 +211,9 @@ int Filesystem::listdir_recursive (std::filesystem::path dir, std::map Date: Mon, 17 Mar 2025 10:29:59 -0500 Subject: [PATCH 05/20] eradicate extra blank line in `Filesystem.cpp` --- library/modules/Filesystem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index 9e81ba8d10..b626319928 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -216,4 +216,3 @@ std::filesystem::path Filesystem::canonicalize(std::filesystem::path p) { return std::filesystem::canonical(p); } - From 951621d5cae7fb1346e12c77f1250b1e8259b5a2 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 11:24:50 -0500 Subject: [PATCH 06/20] don't error on an existing but empty script --- library/Core.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index c4c611ee9d..cb310a4777 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1341,8 +1341,8 @@ bool Core::loadScriptFile(color_ostream &out, std::filesystem::path fname, bool INFO(script,out) << "Running script: " << fname << std::endl; std::cerr << "Running script: " << fname << std::endl; } - std::ifstream script(fname); - if ( !script.good() ) + std::ifstream script{ fname.c_str() }; + if ( !script ) { if(!silent) out.printerr("Error loading script: %s\n", fname.string().c_str()); @@ -2203,9 +2203,9 @@ size_t loadScriptFiles(Core* core, color_ostream& out, const std::vector Date: Mon, 17 Mar 2025 12:17:31 -0500 Subject: [PATCH 07/20] fix stupidly reversed arguments to `relative` --- library/modules/Filesystem.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index b626319928..d95afecf8b 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -49,6 +49,7 @@ SOFTWARE. #include #include #include +#include #include "modules/Filesystem.h" @@ -201,8 +202,9 @@ int Filesystem::listdir_recursive (std::filesystem::path dir, std::mapis_directory() && i.depth() >= depth) i.disable_recursion_pending(); - auto dirent = include_prefix ? *i : std::filesystem::relative(dir, *i); - files.emplace(dirent, i->is_directory()); + auto p = i->path(); + auto pp = include_prefix ? p : std::filesystem::relative(p, dir); + files.emplace(pp, std::filesystem::is_directory(p)); } return 0; } From 0f83cac96f6fd711ec845ac5dc23105ef5962df6 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 12:37:06 -0500 Subject: [PATCH 08/20] fix mtime to return -1 (not 0) on failure --- library/modules/Filesystem.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index d95afecf8b..14f1ec6341 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -169,11 +169,12 @@ std::time_t Filesystem::mtime (std::filesystem::path path) try { auto ftime = std::filesystem::last_write_time(path); - return ftime.time_since_epoch().count(); + auto t = ftime.time_since_epoch().count(); + return t; } catch (std::filesystem::filesystem_error&) { - return 0; + return -1; } } From c4de1207ec8573884a96a4a6dc511d375125f198 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 13:50:57 -0500 Subject: [PATCH 09/20] use filesystem::path for mod script paths also make testing slightly noisier --- ci/test.lua | 1 + library/Core.cpp | 24 ++++++++++++++---------- library/include/Core.h | 8 ++++---- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index e57facf14b..32466a4f9a 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -289,6 +289,7 @@ local MODES = { local function load_test_config(config_file) local config = {} + print ("loading test config from " .. config_file) if dfhack.filesystem.isfile(config_file) then config = json.decode_file(config_file) end diff --git a/library/Core.cpp b/library/Core.cpp index cb310a4777..642ff7d7a6 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -480,10 +480,10 @@ static bool try_autocomplete(color_ostream &con, const std::string &first, std:: return false; } -bool Core::addScriptPath(std::string path, bool search_before) +bool Core::addScriptPath(std::filesystem::path path, bool search_before) { std::lock_guard lock(script_path_mutex); - std::vector &vec = script_paths[search_before ? 0 : 1]; + auto &vec = script_paths[search_before ? 0 : 1]; if (std::find(vec.begin(), vec.end(), path) != vec.end()) return false; if (!Filesystem::isdir(path)) @@ -492,19 +492,19 @@ bool Core::addScriptPath(std::string path, bool search_before) return true; } -bool Core::setModScriptPaths(const std::vector &mod_script_paths) { +bool Core::setModScriptPaths(const std::vector &mod_script_paths) { std::lock_guard lock(script_path_mutex); script_paths[2] = mod_script_paths; return true; } -bool Core::removeScriptPath(std::string path) +bool Core::removeScriptPath(std::filesystem::path path) { std::lock_guard lock(script_path_mutex); bool found = false; for (int i = 0; i < 2; i++) { - std::vector &vec = script_paths[i]; + auto &vec = script_paths[i]; while (1) { auto it = std::find(vec.begin(), vec.end(), path); @@ -547,7 +547,7 @@ std::filesystem::path Core::findScript(std::string name) if (Filesystem::isfile(path)) return path; } - return ""; + return {}; } bool loadScriptPaths(color_ostream &out, bool silent = false) @@ -585,14 +585,18 @@ bool loadScriptPaths(color_ostream &out, bool silent = false) } static void loadModScriptPaths(color_ostream &out) { - std::vector mod_script_paths; + std::vector mod_script_paths_str; + std::vector mod_script_paths; Lua::CallLuaModuleFunction(out, "script-manager", "get_mod_script_paths", {}, 1, [&](lua_State *L) { - Lua::GetVector(L, mod_script_paths); + Lua::GetVector(L, mod_script_paths_str); }); DEBUG(script,out).print("final mod script paths:\n"); - for (auto & path : mod_script_paths) - DEBUG(script,out).print(" %s\n", path.c_str()); + for (auto& path : mod_script_paths_str) + { + DEBUG(script, out).print(" %s\n", path.c_str()); + mod_script_paths.push_back(std::filesystem::canonical(std::filesystem::path{ path })); + } Core::getInstance().setModScriptPaths(mod_script_paths); } diff --git a/library/include/Core.h b/library/include/Core.h index 6794a6b28f..9ef8fb8f0e 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -177,9 +177,9 @@ namespace DFHack command_result runCommand(color_ostream &out, const std::string &command); bool loadScriptFile(color_ostream &out, std::filesystem::path fname, bool silent = false); - bool addScriptPath(std::string path, bool search_before = false); - bool setModScriptPaths(const std::vector &mod_script_paths); - bool removeScriptPath(std::string path); + bool addScriptPath(std::filesystem::path path, bool search_before = false); + bool setModScriptPaths(const std::vector & mod_script_paths); + bool removeScriptPath(std::filesystem::path path); std::filesystem::path findScript(std::string name); void getScriptPaths(std::vector *dest); @@ -273,7 +273,7 @@ namespace DFHack std::vector> allModules; DFHack::PluginManager * plug_mgr; - std::vector script_paths[3]; + std::vector script_paths[3]; std::mutex script_path_mutex; // hotkey-related stuff From 9c8688aea987ce3245365c5a87caec275e40aa46 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 15:12:02 -0500 Subject: [PATCH 10/20] add noisy logging to try to debug ci --- library/Core.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/Core.cpp b/library/Core.cpp index 642ff7d7a6..0fa04d1d08 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -544,6 +544,7 @@ std::filesystem::path Core::findScript(std::string name) for (auto it = paths.begin(); it != paths.end(); ++it) { std::filesystem::path path = *it / name; + std::cerr << "findScript " << name << " | " << path << " | " << Filesystem::isfile(path) << std::endl; if (Filesystem::isfile(path)) return path; } From be1c8e95290ed5445e92b20b152fc8e028b52d8b Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 15:29:12 -0500 Subject: [PATCH 11/20] different noisy crickets --- library/Core.cpp | 1 - library/LuaApi.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index 0fa04d1d08..642ff7d7a6 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -544,7 +544,6 @@ std::filesystem::path Core::findScript(std::string name) for (auto it = paths.begin(); it != paths.end(); ++it) { std::filesystem::path path = *it / name; - std::cerr << "findScript " << name << " | " << path << " | " << Filesystem::isfile(path) << std::endl; if (Filesystem::isfile(path)) return path; } diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index cc8c643b74..c37fd946e7 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -3962,6 +3962,7 @@ static int internal_findScript(lua_State *L) { const char *name = luaL_checkstring(L, 1); std::filesystem::path path = Core::getInstance().findScript(name); + std::cerr << "findScript " << name << " -> " << path << std::endl; if (!path.empty()) lua_pushstring(L, path.string().c_str()); else From 3ee3edf0b2f9f31b7c53a6469fb4894871d24c95 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 15:36:45 -0500 Subject: [PATCH 12/20] switch to weak canonicalization --- library/Core.cpp | 6 +++--- library/modules/Filesystem.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 642ff7d7a6..227c4378f0 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -543,7 +543,7 @@ std::filesystem::path Core::findScript(std::string name) getScriptPaths(&paths); for (auto it = paths.begin(); it != paths.end(); ++it) { - std::filesystem::path path = *it / name; + std::filesystem::path path = std::filesystem::weakly_canonical(*it / name); if (Filesystem::isfile(path)) return path; } @@ -595,7 +595,7 @@ static void loadModScriptPaths(color_ostream &out) { for (auto& path : mod_script_paths_str) { DEBUG(script, out).print(" %s\n", path.c_str()); - mod_script_paths.push_back(std::filesystem::canonical(std::filesystem::path{ path })); + mod_script_paths.push_back(std::filesystem::weakly_canonical(std::filesystem::path{ path })); } Core::getInstance().setModScriptPaths(mod_script_paths); } @@ -1132,7 +1132,7 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s { if(parts.size() == 1) { - loadScriptFile(con, std::filesystem::canonical(std::filesystem::path{parts[0]}), false); + loadScriptFile(con, std::filesystem::weakly_canonical(std::filesystem::path{parts[0]}), false); } else { diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index 14f1ec6341..670e0640ef 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -217,5 +217,5 @@ int Filesystem::listdir_recursive (std::filesystem::path dir, std::map Date: Mon, 17 Mar 2025 16:02:26 -0500 Subject: [PATCH 13/20] make most Filesystem modules noexcept --- library/LuaApi.cpp | 1 - library/include/DataDefs.h | 19 +++++++++++++++ library/include/DataFuncs.h | 35 ++++++++++++++++++++++++++++ library/include/modules/Filesystem.h | 24 +++++++++---------- library/lua/dfhack.lua | 1 + library/modules/Filesystem.cpp | 33 +++++++++++++++----------- 6 files changed, 87 insertions(+), 26 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c37fd946e7..cc8c643b74 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -3962,7 +3962,6 @@ static int internal_findScript(lua_State *L) { const char *name = luaL_checkstring(L, 1); std::filesystem::path path = Core::getInstance().findScript(name); - std::cerr << "findScript " << name << " -> " << path << std::endl; if (!path.empty()) lua_pushstring(L, path.string().c_str()); else diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index c6a7eb8272..6738054423 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -615,6 +615,25 @@ namespace df static const bool is_method = true; }; + template + struct return_type { + using type = RT; + static const bool is_method = false; + }; + + template + struct return_type { + using type = RT; + using class_type = CT; + static const bool is_method = true; + }; + + template + struct return_type { + using type = RT; + using class_type = CT; + static const bool is_method = true; + }; } diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h index e8bfc7e284..a8d2caca51 100644 --- a/library/include/DataFuncs.h +++ b/library/include/DataFuncs.h @@ -133,6 +133,41 @@ namespace df { }; }; + template + struct function_wrapper { + static const int num_args = sizeof...(AT); + static void execute(lua_State* L, int base, RT(fun)(DFHack::color_ostream& out, AT...)) { + cur_lua_ostream_argument out(L); + call_and_push(L, base, fun, out); + } + }; + + template + struct function_wrapper { + static const int num_args = sizeof...(AT); + static void execute(lua_State* L, int base, RT(fun)(AT...)) { + call_and_push(L, base, fun); + } + }; + + template + struct function_wrapper { + static const int num_args = sizeof...(AT) + 1; + static void execute(lua_State* L, int base, RT(CT::* mem_fun)(AT...)) { + CT* self = (CT*)DFHack::LuaWrapper::get_object_addr(L, base++, UPVAL_METHOD_NAME, "invoke"); + call_and_push(L, base, mem_fun, self); + }; + }; + + template + struct function_wrapper { + static const int num_args = sizeof...(AT) + 1; + static void execute(lua_State* L, int base, RT(CT::* mem_fun)(AT...) const) { + CT* self = (CT*)DFHack::LuaWrapper::get_object_addr(L, base++, UPVAL_METHOD_NAME, "invoke"); + call_and_push(L, base, mem_fun, self); + }; + }; + template class function_identity : public function_identity_base { T ptr; diff --git a/library/include/modules/Filesystem.h b/library/include/modules/Filesystem.h index d2b6f7a9b8..c4a1c8ad94 100644 --- a/library/include/modules/Filesystem.h +++ b/library/include/modules/Filesystem.h @@ -56,24 +56,24 @@ SOFTWARE. namespace DFHack { namespace Filesystem { DFHACK_EXPORT void init (); - DFHACK_EXPORT bool chdir (std::filesystem::path path); + DFHACK_EXPORT bool chdir (std::filesystem::path path) noexcept; DFHACK_EXPORT std::filesystem::path getcwd (); DFHACK_EXPORT bool restore_cwd (); DFHACK_EXPORT std::filesystem::path get_initial_cwd (); - DFHACK_EXPORT bool mkdir (std::filesystem::path path); + DFHACK_EXPORT bool mkdir (std::filesystem::path path) noexcept; // returns true on success or if directory already exists - DFHACK_EXPORT bool mkdir_recursive (std::filesystem::path path); - DFHACK_EXPORT bool rmdir (std::filesystem::path path); - DFHACK_EXPORT bool stat (std::filesystem::path path, std::filesystem::file_status &info); - DFHACK_EXPORT bool exists (std::filesystem::path path); - DFHACK_EXPORT bool isfile (std::filesystem::path path); - DFHACK_EXPORT bool isdir (std::filesystem::path path); - DFHACK_EXPORT std::time_t mtime (std::filesystem::path path); - DFHACK_EXPORT int listdir (std::filesystem::path dir, std::vector &files); + DFHACK_EXPORT bool mkdir_recursive (std::filesystem::path path) noexcept; + DFHACK_EXPORT bool rmdir (std::filesystem::path path) noexcept; + DFHACK_EXPORT bool stat (std::filesystem::path path, std::filesystem::file_status &info) noexcept; + DFHACK_EXPORT bool exists (std::filesystem::path path) noexcept; + DFHACK_EXPORT bool isfile (std::filesystem::path path) noexcept; + DFHACK_EXPORT bool isdir (std::filesystem::path path) noexcept; + DFHACK_EXPORT std::time_t mtime (std::filesystem::path path) noexcept; + DFHACK_EXPORT int listdir (std::filesystem::path dir, std::vector &files) noexcept; // set include_prefix to false to prevent dir from being prepended to // paths returned in files DFHACK_EXPORT int listdir_recursive (std::filesystem::path dir, std::map &files, - int depth = 10, bool include_prefix = true); - DFHACK_EXPORT std::filesystem::path canonicalize(std::filesystem::path p); + int depth = 10, bool include_prefix = true) noexcept; + DFHACK_EXPORT std::filesystem::path canonicalize(std::filesystem::path p) noexcept; } } diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index ef08fb7f4b..88327a419e 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -1074,6 +1074,7 @@ function dfhack.run_script_with_env(envVars, name, flags, ...) end end + print ( "run_script_with_env, name="..name..", file="..file ) local env = scripts[file].env if env == nil then env = {} diff --git a/library/modules/Filesystem.cpp b/library/modules/Filesystem.cpp index 670e0640ef..55a7fd2194 100644 --- a/library/modules/Filesystem.cpp +++ b/library/modules/Filesystem.cpp @@ -67,7 +67,7 @@ void Filesystem::init () } } -bool Filesystem::chdir (std::filesystem::path path) +bool Filesystem::chdir (std::filesystem::path path) noexcept { Filesystem::init(); try @@ -97,7 +97,7 @@ std::filesystem::path Filesystem::get_initial_cwd () return initial_cwd; } -bool Filesystem::mkdir (std::filesystem::path path) +bool Filesystem::mkdir (std::filesystem::path path) noexcept { try { @@ -110,7 +110,7 @@ bool Filesystem::mkdir (std::filesystem::path path) } } -bool Filesystem::mkdir_recursive (std::filesystem::path path) +bool Filesystem::mkdir_recursive (std::filesystem::path path) noexcept { try { @@ -123,7 +123,7 @@ bool Filesystem::mkdir_recursive (std::filesystem::path path) } } -bool Filesystem::rmdir (std::filesystem::path path) +bool Filesystem::rmdir (std::filesystem::path path) noexcept { try { @@ -136,7 +136,7 @@ bool Filesystem::rmdir (std::filesystem::path path) } } -bool Filesystem::stat (std::filesystem::path path, std::filesystem::file_status &info) +bool Filesystem::stat (std::filesystem::path path, std::filesystem::file_status &info) noexcept { try { @@ -149,22 +149,22 @@ bool Filesystem::stat (std::filesystem::path path, std::filesystem::file_status } } -bool Filesystem::exists (std::filesystem::path path) +bool Filesystem::exists (std::filesystem::path path) noexcept { return std::filesystem::exists(path); } -bool Filesystem::isfile(std::filesystem::path path) +bool Filesystem::isfile(std::filesystem::path path) noexcept { return std::filesystem::exists(path) && std::filesystem::is_regular_file(path); } -bool Filesystem::isdir (std::filesystem::path path) +bool Filesystem::isdir (std::filesystem::path path) noexcept { return std::filesystem::exists(path) && std::filesystem::is_directory(path); } -std::time_t Filesystem::mtime (std::filesystem::path path) +std::time_t Filesystem::mtime (std::filesystem::path path) noexcept { try { @@ -178,7 +178,7 @@ std::time_t Filesystem::mtime (std::filesystem::path path) } } -int Filesystem::listdir (std::filesystem::path dir, std::vector &files) +int Filesystem::listdir (std::filesystem::path dir, std::vector &files) noexcept { try { for (auto const& dirent : std::filesystem::directory_iterator(dir)) @@ -194,7 +194,7 @@ int Filesystem::listdir (std::filesystem::path dir, std::vector &files, - int depth /* = 10 */, bool include_prefix /* = true */) + int depth /* = 10 */, bool include_prefix /* = true */) noexcept { try { for (auto i = std::filesystem::recursive_directory_iterator(dir); @@ -215,7 +215,14 @@ int Filesystem::listdir_recursive (std::filesystem::path dir, std::map Date: Mon, 17 Mar 2025 16:20:45 -0500 Subject: [PATCH 14/20] more cricket shuffling --- library/lua/dfhack.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 88327a419e..97351e8825 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -1042,7 +1042,9 @@ end function dfhack.run_script_with_env(envVars, name, flags, ...) if type(flags) ~= 'table' then flags = {} end + dfhack.printerr ( "run_script_with_env, name="..name..", file=" ) local file = dfhack.findScript(name) + dfhack.printerr ( "run_script_with_env, name="..name..", file="..file ) if not file then error('Could not find script ' .. name) end @@ -1074,7 +1076,6 @@ function dfhack.run_script_with_env(envVars, name, flags, ...) end end - print ( "run_script_with_env, name="..name..", file="..file ) local env = scripts[file].env if env == nil then env = {} From 5beb9405bfb570b6c3f51ab27ffcc9b95ba4dd8e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 16:34:31 -0500 Subject: [PATCH 15/20] more cricket shuffling --- library/Core.cpp | 1 + library/lua/dfhack.lua | 1 + 2 files changed, 2 insertions(+) diff --git a/library/Core.cpp b/library/Core.cpp index 227c4378f0..4d0a505d06 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -350,6 +350,7 @@ static bool init_run_script(color_ostream &out, lua_State *state, void *info) static command_result runLuaScript(color_ostream &out, std::string name, std::vector &args) { + std::cerr << "runLuaScript " << name << std::endl; ScriptArgs data; data.pcmd = &name; data.pargs = &args; diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 97351e8825..888a266d14 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -997,6 +997,7 @@ local valid_script_flags = { local warned_scripts = {} function dfhack.run_script(name,...) + dfhack.printerr ( "run_script, name="..name ) if not warned_scripts[name] then local helpdb = require('helpdb') if helpdb.has_tag(name, 'unavailable') then From 6ab84505d402f6eaf7b0fceda08cd6f783c01ce8 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 16:48:31 -0500 Subject: [PATCH 16/20] better type jenga (???) --- library/LuaTools.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index c0f8bd1d2e..084ba4be3e 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -1240,13 +1240,13 @@ bool DFHack::Lua::RunCoreQueryLoop(color_ostream &out, lua_State *state, if (histfile != histname) { if (!histname.empty()) - hist.save(histname.c_str()); + hist.save(std::filesystem::path{ histname }); hist.clear(); histname = histfile; if (!histname.empty()) - hist.load(histname.c_str()); + hist.load(std::filesystem::path{ histname }); } if (prompt.empty()) @@ -1269,7 +1269,7 @@ bool DFHack::Lua::RunCoreQueryLoop(color_ostream &out, lua_State *state, } if (!histname.empty()) - hist.save(histname.c_str()); + hist.save(std::filesystem::path{ histname }); { CoreSuspender suspend; From 8979fe2535e95b320f05841bf5a14b8c1276941f Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 17:04:13 -0500 Subject: [PATCH 17/20] fix a couple more type jengas --- library/Core.cpp | 2 ++ library/LuaApi.cpp | 2 +- library/LuaTools.cpp | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 4d0a505d06..a1cdcbac41 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -357,6 +357,8 @@ static command_result runLuaScript(color_ostream &out, std::string name, std::ve bool ok = Lua::RunCoreQueryLoop(out, DFHack::Core::getInstance().getLuaState(true), init_run_script, &data); + std::cerr << "runLuaScript " << name << " res=" << ok << std::endl; + return ok ? CR_OK : CR_FAILURE; } diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index cc8c643b74..e082076ae6 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1290,7 +1290,7 @@ static void addCommandToHistory(string id, string src_file, string command) { CommandHistory *history = ensureCommandHistory(id, src_file); history->add(command); - history->save(src_file.c_str()); + history->save(std::filesystem::path{ src_file }); } /************************ diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 084ba4be3e..2d9df61ab4 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -426,7 +426,7 @@ static int dfhack_lineedit_sync(lua_State *S, Console *pstream) DFHack::CommandHistory hist; if (hfile) - hist.load(hfile); + hist.load(std::filesystem::path{ hfile }); std::string ret; int rv = pstream->lineedit(prompt, ret, hist); @@ -446,7 +446,7 @@ static int dfhack_lineedit_sync(lua_State *S, Console *pstream) else { if (hfile) - hist.save(hfile); + hist.save(std::filesystem::path{ hfile }); lua_pushlstring(S, ret.data(), ret.size()); return 1; } From b98913b6ed6c0b0525f12d49ce8a295a2c86ab59 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 17:15:17 -0500 Subject: [PATCH 18/20] add missing slash --- ci/test.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.lua b/ci/test.lua index 32466a4f9a..c0d021d0a6 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -295,7 +295,7 @@ local function load_test_config(config_file) end if not config.test_dir then - config.test_dir = dfhack.getHackPath() .. 'scripts/test' + config.test_dir = dfhack.getHackPath() .. '/scripts/test' end if not config.save_dir then From 5683c7aee513fe3aec1276748083612734a655e4 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 17:24:35 -0500 Subject: [PATCH 19/20] silence at least some of the crickets --- library/Core.cpp | 3 --- library/lua/dfhack.lua | 3 --- 2 files changed, 6 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index a1cdcbac41..227c4378f0 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -350,15 +350,12 @@ static bool init_run_script(color_ostream &out, lua_State *state, void *info) static command_result runLuaScript(color_ostream &out, std::string name, std::vector &args) { - std::cerr << "runLuaScript " << name << std::endl; ScriptArgs data; data.pcmd = &name; data.pargs = &args; bool ok = Lua::RunCoreQueryLoop(out, DFHack::Core::getInstance().getLuaState(true), init_run_script, &data); - std::cerr << "runLuaScript " << name << " res=" << ok << std::endl; - return ok ? CR_OK : CR_FAILURE; } diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 888a266d14..ef08fb7f4b 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -997,7 +997,6 @@ local valid_script_flags = { local warned_scripts = {} function dfhack.run_script(name,...) - dfhack.printerr ( "run_script, name="..name ) if not warned_scripts[name] then local helpdb = require('helpdb') if helpdb.has_tag(name, 'unavailable') then @@ -1043,9 +1042,7 @@ end function dfhack.run_script_with_env(envVars, name, flags, ...) if type(flags) ~= 'table' then flags = {} end - dfhack.printerr ( "run_script_with_env, name="..name..", file=" ) local file = dfhack.findScript(name) - dfhack.printerr ( "run_script_with_env, name="..name..", file="..file ) if not file then error('Could not find script ' .. name) end From 4a8b292438dc36e94967639523bcf0980e42259f Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 17 Mar 2025 17:35:57 -0500 Subject: [PATCH 20/20] use same cwd mechanics in both linux and windows --- library/Process-windows.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/library/Process-windows.cpp b/library/Process-windows.cpp index fe8c5d591a..603636176d 100644 --- a/library/Process-windows.cpp +++ b/library/Process-windows.cpp @@ -33,11 +33,13 @@ distribution. #include "Error.h" #include "Internal.h" + #include "MemAccess.h" #include "Memory.h" #include "MiscUtils.h" #include "VersionInfo.h" #include "VersionInfoFactory.h" +#include "modules/Filesystem.h" #define _WIN32_WINNT 0x0600 #define WINVER 0x0600 @@ -384,13 +386,7 @@ uint32_t Process::getTickCount() std::filesystem::path Process::getPath() { - HMODULE hmod; - DWORD junk; - char String[255]; - EnumProcessModules(d->my_handle, &hmod, 1 * sizeof(HMODULE), &junk); //get the module from the handle - GetModuleFileNameEx(d->my_handle,hmod,String,sizeof(String)); //get the filename from the module - string out(String); - return(out.substr(0,out.find_last_of("\\"))); + return Filesystem::get_initial_cwd(); } int Process::getPID()