Which interpreters comply with ZMS 1.1 regarding prompt parameter of @save/@restore opcodes?

Are there any interpreters for Z-Machine that obey the Standard 1.1 directive that a prompt parameter for the @save and @restore opcodes can be given to suppress prompting the user for a filename? The relevant text is:

***[1.1] As of Standard 1.1 an additional optional parameter, prompt, is allowed on
Version 5 extended save/restore. This allows a game author to tell the interpreter whether it
should ask for confirmation of the provided file name (prompt is 1), or just silently
save/restore using the provided filename (prompt is 0). If the parameter is not provided,
whether to prompt or not is a matter for the interpreter - this might be globally user-
configurable. Infocom’s interpreters do prompt for filenames, many modern ones do not.

The version of Frotz in gargoyle the I7 IDE for Linux (I think Frotz 2.50) reports 1.1 compliance but seems to ignore the prompt parameter of the opcode. A filename prompt is produce regardless of whether prompt is 0 or 1. (EDIT: It looks like I was mixing up my interpreters before.)

I know that WinFrotz obeys the prompt parameter, but I’m not aware of any other interpreters that do. EDIT: Per the efforts of DavidG and cas (see below), support for this feature has now been added to both Frotz and Bocfel (used by Gargoyle).

1 Like

I never got around to implementing any of the additional operands on @save in ZVM, but no one ever asked about them either. And it does claim to be a 1.1 interpreter…

1 Like

What test program were you using?

Here’s a short example program.

Constant Story "save/restore prompt parameter";
Constant Headline "^(a ZMS 1.1 compliance test)^";

Include "Parser";
Include "VerbLib";
Include "Grammar";

Array hopcount --> 1;

Array savename string "hopcount.aux";

Class Room
    has light;

Room Start "Starting Point"
    with    description
                "An uninteresting room.",
            before [;
                Jump: print_ret "Hop count = ", ++(hopcount-->0), ".";
                WaveHands: SilentSave();
                Wait: SilentRestore();
            ];

[ SilentSave result ;
    @save hopcount 2 savename 0 -> result;
];

[ SilentRestore result ;
    @restore hopcount 2 savename 0 -> result;
];

[ Initialise ;

    location = Start;

    print ">JUMP   --   increase counter^";
    print ">WAVE   --   save counter (silently, in theory)^";
    print ">WAIT   --   restore counter (silently, in theory)^";

];
2 Likes

Thanks. I’ll go over this tomorrow and see what’s going on in the current Frotz code.

I filed an issue on this at https://gitlab.com/DavidGriffith/frotz/-/issues/258, fixed the oversight, and closed out that issue.

Thank you @otistdog for bringing this to my attention.

3 Likes

Thank you! That makes two major interpreters that support this aspect of the ZMS 1.1 standard.

Any chance of Bocfel (which is the Z-Machine interpreter actually used by Gargoyle) being updated to support this feature? The version of Gargoyle released in 2019 seems to use Bocfel 1.0.1, which also ignores the prompt parameter for these opcodes. There are some newer versions available, but I don’t see anything in the change notes (Downloads - Bocfel) that seems relevant to this. Is that maintained by @cas?

Maybe… I’ve intentionally kept this unimplemented because I’m wary of allowing arbitrary files to be written by a game. Unfortunately, due to the fact that Glk doesn’t allow filename suggestions, that means that if a game is trying to save a specific file, unprompted, the user will be shown a dialog with some name supplied by the Glk implementation (e.g. Untitled.glksave). This isn’t exactly user friendly.

I’d probably be comfortable adding unprompted save files which are confined to their own per-game directory. At least then the game can’t do anything but overwrite its own files, which is perfectly valid.

How many games are there out in the wild which use these extended save/restore features? I know SameGame does for high scores, but I’m not aware of any others.

1 Like

I think it’s something of a chicken-and-egg problem. There’s not much point in using a feature that’s not supported by the most popular interpreters. There are several Glulx games that use silent file writes and reads, I believe.

I know effectively nothing about Glk, but I’m looking at the specification. I think section 6 (Glk: A Portable Interface Standard for IF) is the governing portion, and it seems to explicitly support this kind of activity:

A fileref does not have to refer to a file which actually exists. You can create a fileref for a nonexistent file, and then open it in write mode to create a new file.

and:

When a fileref is created non-interactively (glk_fileref_create_by_name, glk_fileref_create_temp) the default rules always apply.

and in Section 6.1, regarding glk_fileref_create_by_name():

This creates a reference to a file with a specific name. The file will be in a fixed location relevant to your program, and visible to the player. [This usually means “in the same directory as your program.”]

Is that not the function that could be used to write a file with a name specified by the author instead of the player?

For sure, and I’m not using that as an excuse to not implement silent reads/writes; just a general interest in how common it is. In fact, I’ve just finished up an implementation for Bocfel, and I ought to be able to backport it to the 1.4 branch and get it into the next Gargoyle release.

Glk can open arbitrary (-ish) files, yes; but the issue I was referring to is the fact that Glk cannot display a prompt with a suggested filename (per the 1.1 requirement). Any suggested filename is entirely up to the Glk implementation.

A possible solution is a Gargoyle extension which allows a suggested filename. I don’t really want to extend Gargoyle too far past standard Glk, but it might be worth doing.

2 Likes

I was preoccupied with V6 EGA graphics conversions and didn’t ponder this as deeply as I should have. Your concerns are spot on. I’m not sure I’ll want to keep this in Frotz. If I leave it in, I want to restrict the filename to <gamename>.aux. Without restrictions, this is asking for trouble.

Regarding that type of concern, section 6.1 of the Glk specification goes on to say:

Earlier versions of the Glk spec specified that the library may have to extend, truncate, or change your name argument in order to produce a legal native filename. This remains true. However, since Glk was originally proposed, the world has largely reached concensus about what a filename looks like. Therefore, it is worth including some recommended library behavior here. Libraries that share this behavior will more easily be able to exchange files, which may be valuable both to authors (distributing data files for games) and for players (moving data between different computers or different applications).

The library should take the given filename argument, and delete any characters illegal for a filename. This will include all of the following characters (and more, if the OS requires it): slash, backslash, angle brackets (less-than and greater-than), colon, double-quote, pipe (vertical bar), question-mark, asterisk. The library should also truncate the argument at the first period (delete the first period and any following characters). If the result is the empty string, change it to the string “null”.

It should then append an appropriate suffix, depending on the usage: “.glkdata” for fileusage_Data, “.glksave” for fileusage_SavedGame, “.txt” for fileusage_Transcript and fileusage_InputRecord.

Perhaps those are useful guidelines that would help to create consistency across interpreters. I would suggest leaving period characters as an option, so that an author can invent an ID for their work and ask for files with names like “data1.storyid”, which could translate to a file data1.storyid.aux.

Thank you very much! That’s terrific news. Three major Z-Machine interpreters, now.

I’m revisiting this issue and why I reverted it from Frotz. My problem with it is that reading or writing arbitrary files without prompting the user is a big security risk, especially when running code from who-knows-where. The Z-machine’s design guards against that somewhat by asking whenever something is read or written. Why was this additional parameter added in the first place? What games make use of it?

It is an implicit expectation of Inform 6; see Exercise 137 in DM4 (p. 319, solution p. 515).

Six is an example of a game that does this, though that is Glulx. I don’t know that there are Z-machine games that use this feature, because support for the spec behavior has been missing.

The suggested restrictions (i.e. ensuring a “.aux” suffix, limiting file location to the game directory) make sense and don’t seem problematic to me given what I understood to be the intended utility.

Just a quick note here: what I implemented in Bocfel is the feature of auxiliary files themselves, not the prompting part, since Glk doesn’t have a way to make that possible.

However, as I noted, a Glk extension could be added just for this, and while I was reluctant at first, I did add an extension to support Z-machine bleeps, so it’d be pretty hypocritical to reject the idea of an extension for something that has, certainly, at least as much utility as bleeps. I’ll find some time to see how feasible this would be.

1 Like

In light of this, I decided to proceed with implementing this. So far I have the the curses, X11, and DOS interfaces done along with restricting the file access to .aux files. SDL does things a bit stranger than the other interfaces, so that’s still in the works. I’m uncertain about doing this for the dumb interface because what I’ve been doing requires vsnprintf() and I’m not sure about support for the va_list functions in some of the super-old C compilers.

[edit]

I checked KCC, the main C compiler for use on the PDP-10 line of mainframes. It supports the va_list functions, so I’ll proceed with adding them to the dumb interface. Now to see what’s necessary for the PDP-11…

I have completed implementing this for all interfaces in the Unix Frotz suite. Currently it restricts unprompted access to *.aux files. Now I’m looking into how best to restrict the path of files so accessed.

Look for a new release of Frotz soon because I came across some questionable coding practice in the SDL interface. This caused GCC 12 to throw errors and refuse to compile. When “fixed” simply, there were graphical problems. I’m not clear why earlier versions of GCC didn’t have these problems with the SDL interface. That problem has now been fixed.

1 Like

I think my work on support for this for the Unix Frotz suite is complete. I decided that restricting the unprompted .aux file to the directory specified by the -R flag is enough. I’m moving on to ensuring that Frotz is now in complete compliance with ZMS 1.1.