From 0455657ed5dbaf697936ae08dcbf78fb3523f9ad Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Fri, 4 Sep 2026 19:33:02 -0500 Subject: [PATCH] More vfs fixes. --- .gitignore | 6 ++++++ CHANGELOG | 3 +++ assets/Framework.singe | 4 +++- docs/Manual.adoc | 4 ++-- src/main.c | 9 +++++---- src/vfs.c | 6 +++++- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 02320104b..b133aba1e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,9 @@ docs/Manual.html docs/Manual.pdf docs/.asciidoctor/ .claude/settings.local.json + +# Extracted by the binary when it is run from here; never source. +/Singe/ +/Menu.sh +/Menu.bat +/data/ diff --git a/CHANGELOG b/CHANGELOG index 3f202d677..adf81f787 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -10,6 +10,9 @@ API Changes - The name now expands to "SINGE Is Not a Game Emulator", in the banner, the manual, INSTALL, and the Windows file description. +- Framework.singe applies the legacy sprite argument order once even when + a game loads it more than once. + - lfs.dir, lfs.attributes and lfs.symlinkattributes see inside a packed game (the union of its loose directory, its data overlay and the database), and lfs.mkdir and lfs.rmdir act on its data overlay, so diff --git a/assets/Framework.singe b/assets/Framework.singe index c0b908805..aef62cdea 100644 --- a/assets/Framework.singe +++ b/assets/Framework.singe @@ -422,7 +422,9 @@ end -- Singe 3.00 moved the sprite handle to the first argument. Games written for -- 2.10 can set SINGE_LEGACY_SPRITE_ARGS = true (or LEGACY_SPRITE_ARGS = true in -- games.dat) to keep calling the old way. -if SINGE_LEGACY_SPRITE_ARGS and spriteDraw ~= nil then +if SINGE_LEGACY_SPRITE_ARGS and spriteDraw ~= nil and not SINGE_LEGACY_SPRITE_WRAPPED then + -- Once only: a game may load this file more than once, and a second wrap would undo the first. + SINGE_LEGACY_SPRITE_WRAPPED = true local newSpriteDraw = spriteDraw spriteDraw = function(...) local args = { ... } diff --git a/docs/Manual.adoc b/docs/Manual.adoc index 5bec9aa9c..ffde49f1d 100644 --- a/docs/Manual.adoc +++ b/docs/Manual.adoc @@ -102,10 +102,10 @@ options available to be used in this file, read through === Command Line Options ---- -Singe [OPTIONS] scriptName{.singe} +Singe [OPTIONS] gameName ---- -The script name is the only required argument. It may be a `.singe` file, a +The game name is the only required argument. It may be a `.singe` script, a directory containing a script of the same name (`ActionMax` finds `ActionMax/ActionMax.singe`), or a packed game (`DLe.game` runs the first entry of the `games.dat` inside it, `--entry=N` another). For a laserdisc game (`--disc`) with no diff --git a/src/main.c b/src/main.c index 94a672595..dd70bb8b0 100644 --- a/src/main.c +++ b/src/main.c @@ -527,7 +527,7 @@ static ConfigT *_parseArguments(const char *exeName, int32_t argc, char *argv[]) // Non-option: the script file. case 0: if (conf->scriptFile) { - _showUsage(exeName, "Only one script file may be specified."); + _showUsage(exeName, "Only one game may be specified."); } conf->scriptFile = strdup(arg); break; @@ -819,7 +819,7 @@ static void _resolveFiles(const char *exeName, ConfigT *conf) { conf->scriptFile = temp; } if (!conf->scriptFile) { - _showUsage(exeName, "Unable to locate script."); + _showUsage(exeName, "Unable to locate the game."); } // Do we need to generate a video name? @@ -918,7 +918,8 @@ static void _showUsage(const char *name, const char *message) { _showHeader(); - utilSay("Usage: %s [OPTIONS] scriptName{.singe}", utilGetLastPathComponent(name)); + utilSay("Usage: %s [OPTIONS] gameName", utilGetLastPathComponent(name)); + utilSay(" gameName: a .singe script, its directory, or a packed .game file"); utilNewline(); for (x = 0; x < (int32_t)OPTION_COUNT; x++) { if (_options[x].hidden) { @@ -1236,7 +1237,7 @@ int main(int argc, char *argv[]) { // Nothing to run? Installing was the whole job. if (!conf->scriptFile) { - _showUsage(exeName, "No script file specified."); + _showUsage(exeName, "No game specified."); } // A game database on its own runs its first games.dat entry; a patch is not a game. diff --git a/src/vfs.c b/src/vfs.c index 9a85a2f7b..c891bc011 100644 --- a/src/vfs.c +++ b/src/vfs.c @@ -336,7 +336,7 @@ static void _listDirectory(const char *path, char ***list, int32_t *count) { } -// Forward slashes, no leading "./", no doubled slashes. Case is untouched. +// Forward slashes, no leading "./", no doubled or trailing slashes. Case is untouched. static char *_normalise(const char *name) { char *out = strdup(name); size_t i = 0; @@ -354,6 +354,10 @@ static char *_normalise(const char *name) { } out[o++] = c; } + // A trailing separator names the same thing ("Overlay/" is "Overlay"), except for the root. + while ((o > 1) && (out[o - 1] == '/')) { + o--; + } out[o] = 0; return out;