From 683facc8e9bc374d2ba07dc85453919b85cad27c Mon Sep 17 00:00:00 2001 From: Lars Viklund Date: Sat, 28 Jun 2025 20:13:07 +1200 Subject: [PATCH 1/2] feat: expose root paths as both UTF-8 and ACP The standard encoding for all the top level paths (base, script, user) in SimpleGraphic is UTF-8. For some purposes it's useful to know if the path can be expressed in the user's active codepage as well, the updater can use it to form absolute paths that the OS understands. As the user path is fallible, we also expose a human-readable reason as to why it could not be obtained. All paths are made weakly canonical rather than fully canonical as the full flavour requires paths to fully exist. --- engine/system/sys_main.h | 1 + engine/system/win/sys_main.cpp | 38 +++++++++++------------ ui_api.cpp | 56 ++++++++++++++++++++++++++++------ 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/engine/system/sys_main.h b/engine/system/sys_main.h index 1e662f1..5d83fc7 100644 --- a/engine/system/sys_main.h +++ b/engine/system/sys_main.h @@ -69,6 +69,7 @@ class sys_IMain { int processorCount = 0; std::filesystem::path basePath; std::optional userPath; + std::optional userPathReason; virtual int GetTime() = 0; virtual void Sleep(int msec) = 0; diff --git a/engine/system/win/sys_main.cpp b/engine/system/win/sys_main.cpp index 51dec7e..3078e0d 100644 --- a/engine/system/win/sys_main.cpp +++ b/engine/system/win/sys_main.cpp @@ -564,9 +564,9 @@ std::filesystem::path FindBasePath() progPath = basePath.data(); #elif __linux__ char basePath[PATH_MAX]; - ssize_t len = ::readlink("/proc/self/exe", basePath, sizeof(basePath)); - if (len == -1 || len == sizeof(basePath)) - len = 0; + ssize_t len = ::readlink("/proc/self/exe", basePath, sizeof(basePath)); + if (len == -1 || len == sizeof(basePath)) + len = 0; basePath[len] = '\0'; progPath = basePath; #elif __APPLE__ && __MACH__ @@ -575,34 +575,34 @@ std::filesystem::path FindBasePath() proc_pidpath(pid, basePath, sizeof(basePath)); progPath = basePath; #endif - progPath = canonical(progPath); + progPath = weakly_canonical(progPath); return progPath.parent_path(); } -std::optional FindUserPath() +std::tuple, std::optional> FindUserPath() { #ifdef _WIN32 - PWSTR osPath{}; - HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &osPath); + PWSTR osPath{}; + HRESULT hr = SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &osPath); if (FAILED(hr)) { // The path may be inaccessible due to malfunctioning cloud providers. CoTaskMemFree(osPath); - return {}; + return { {}, "Could not obtain Documents path from Windows" }; } std::wstring pathStr = osPath; CoTaskMemFree(osPath); std::filesystem::path path(pathStr); - return canonical(path); + return { weakly_canonical(path), {} }; #else - if (char const* data_home_path = getenv("XDG_DATA_HOME")) { - return data_home_path; - } - if (char const* home_path = getenv("HOME")) { - return std::filesystem::path(home_path) / ".local/share"; - } - uid_t uid = getuid(); - struct passwd *pw = getpwuid(uid); - return std::filesystem::path(pw->pw_dir) / ".local/share"; + if (char const* data_home_path = getenv("XDG_DATA_HOME")) { + return { data_home_path, {} }; + } + if (char const* home_path = getenv("HOME")) { + return { std::filesystem::path(home_path) / ".local/share", {} }; + } + uid_t uid = getuid(); + struct passwd *pw = getpwuid(uid); + return { std::filesystem::path(pw->pw_dir) / ".local/share", {} }; #endif } @@ -628,7 +628,7 @@ sys_main_c::sys_main_c() // Set the local system information basePath = FindBasePath(); - userPath = FindUserPath(); + std::tie(userPath, userPathReason) = FindUserPath(); } bool sys_main_c::Run(int argc, char** argv) diff --git a/ui_api.cpp b/ui_api.cpp index aaa4694..3dba0b1 100644 --- a/ui_api.cpp +++ b/ui_api.cpp @@ -85,9 +85,9 @@ ** compressed = Deflate(uncompressed) ** uncompressed = Inflate(compressed) ** msec = GetTime() -** path = GetScriptPath() -** path = GetRuntimePath() -** path = GetUserPath() -- may return nil if the user path could not be determined +** path[, pathACP[, err]] = GetScriptPath() +** path[, pathACP[, err]] = GetRuntimePath() +** path[, pathACP[, err]] = GetUserPath() -- may return nil if the user path could not be determined ** SetWorkDir("") ** path = GetWorkDir() ** ssID = LaunchSubScript("", "", ""[, ...]) @@ -1544,25 +1544,63 @@ static int l_GetScriptPath(lua_State* L) { ui_main_c* ui = GetUIPtr(L); lua_pushstring(L, ui->scriptPath.generic_u8string().c_str()); - return 1; + try + { + lua_pushstring(L, ui->scriptPath.generic_string().c_str()); + return 2; + } + catch (std::exception& e) + { + lua_pushnil(L); + lua_pushstring(L, e.what()); + return 3; + } } static int l_GetRuntimePath(lua_State* L) { ui_main_c* ui = GetUIPtr(L); lua_pushstring(L, ui->sys->basePath.generic_u8string().c_str()); - return 1; + try + { + lua_pushstring(L, ui->sys->basePath.generic_string().c_str()); + return 2; + } + catch (std::exception& e) + { + lua_pushnil(L); + lua_pushstring(L, e.what()); + return 3; + } } static int l_GetUserPath(lua_State* L) { ui_main_c* ui = GetUIPtr(L); auto& userPath = ui->sys->userPath; - if (userPath) { - lua_pushstring(L, userPath->generic_u8string().c_str()); - return 1; + if (!userPath) { + lua_pushnil(L); + lua_pushnil(L); + if (auto& reason = ui->sys->userPathReason) + { + lua_pushstring(L, reason->c_str()); + return 3; + } + return 2; + } + + lua_pushstring(L, userPath->generic_u8string().c_str()); + try + { + lua_pushstring(L, userPath->generic_string().c_str()); + return 2; + } + catch (std::exception& e) + { + lua_pushnil(L); + lua_pushstring(L, e.what()); + return 3; } - return 0; } static int l_MakeDir(lua_State* L) From de7a6fdfebf25ab76ad6f599bfb5735708faf7aa Mon Sep 17 00:00:00 2001 From: Lars Viklund Date: Sat, 28 Jun 2025 20:15:03 +1200 Subject: [PATCH 2/2] fix: remove extra invalid glyphs in text draws Whenever an invalid code unit was detected, a placeholder should be emitted. This change fixes a bug where it also wrote out the original code unit as-is. --- engine/common/common.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/common/common.cpp b/engine/common/common.cpp index 3340bad..01860a1 100644 --- a/engine/common/common.cpp +++ b/engine/common/common.cpp @@ -484,7 +484,7 @@ IndexedUTF32String IndexUTF8ToUTF32(std::string_view input) byteIdx += 4; } else { - codepoints.push_back(0xFFFDu); + codepoint = 0xFFFDu; byteIdx += 1; } codepoints.push_back(codepoint);