More vfs fixes.

This commit is contained in:
Scott Duensing 2026-09-04 19:33:02 -05:00
parent 141b388b92
commit 0455657ed5
6 changed files with 24 additions and 8 deletions

6
.gitignore vendored
View file

@ -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/

View file

@ -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

View file

@ -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 = { ... }

View file

@ -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

View file

@ -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.

View file

@ -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;