File I/O

Most every IF system has some provision for file input/output, even if it's merely to create and read saved game files. Glulx Inform allows the programmer to create and read files with any sort of content they like. For instance, you might want to write a series of games featuring the same character, and transfer information about that character from each game to its sequel. This is easily done by having the first game create a file containing the relevant information and having the second one read it in. Here's how.

To create a file, first you must create an object known as a fileref so that the program has a way to refer to it. This is done one of two ways. If you'd like to hardwire the name of the file into the program, the command is glk_fileref_create_by_name; if you'd prefer for the player to select the filename, you want glk_fileref_create_by_prompt. Both of these take three arguments.

The first argument is the information about the type of file to be created. It consists of two constants, joined by a plus sign. The first constant will be "fileusage_Data" (the alternatives here are only used by game-saving routines and the like.) The second will be either fileusage_BinaryMode or fileusage_TextMode; BinaryMode is for files which will be read by Glulx games (such as in the character storage example above) while TextMode is for files which are to be read by the user (a list of amusing things to try, or a certificate of completion, or what have you.)

The third argument (we'll get to the second in a moment) is the rock for the file to be created. Rocks for filerefs are handled just as they are for windows or sound channels. Of course, if you're just creating a file, writing information to it, and closing it, you don't need a rock, since rocks are for keeping track of objects and nothing can occur in that brief a period to cause Glulx to lose track in the first place. If that is the case, you can just use 0 here; if you're keeping the fileref open for multiple turns, however, create a rock for it as usual.

The second argument depends on the file creation method. If you're creating by a name you the programmer are selection, this is where the filename goes. Two complications arise, however. First of all, you want your filename to work across platforms, so your safest bet is to make the name eight characters or less (since some platforms can't handle anything longer) and with no extension (since some platforms don't recognize them.) Secondly, you can't just put the name of the file in this spot, but have to wrap it in a special call, ConvertAnyToCString(). So, to create a file named INFO to stick our data in, we'd end up with:

   fref = glk_fileref_create_by_name(fileusage_Data+fileusage_BinaryMode,

      ConvertAnyToCString("INFO"), 0);

If we're letting the user choose the filename, the second argument contains the information about the type of file to be created. In fact, since these same commands are used for selecting files to read in addition to creating files to write to, there are four options here:

In this case, then, we'd end up with a call like so:

   fref = glk_fileref_create_by_prompt(fileusage_Data+fileusage_BinaryMode,

      filemode_Write, 0);

Once you've got the fileref, you can open the file.

   str = glk_stream_open_file(fref, filemode_Write, 0);

The second argument is one of the filemodes listed above. If you prompted for the file, it should be the same filemode you used before.

Now that the file is open, we can throw away the fileref:


To write, set the current output stream to this file and print normally:


   print "EXPERIENCE POINTS: ", player.exp, "^";

Then set output back to the story window, and close the stream:


   glk_stream_close(str, 0);

The second argument of glk_stream_close(), like that of glk_window_close(), is only interesting if you want to count how many characters were written or read. Everyone else, use zero.

To read a file, the process is much the same, only using filemode_Read. The functions to read data are glk_get_char_stream() to read a single character, glk_get_buffer_stream() to read an array of bytes, and glk_get_line_stream() to read a line of bytes up to the next linebreak.

See the Ork package for more. (Ork 1 generates a file with information about the player character; Ork 2 allows players to load in that character if they wish, or start fresh.)

Return to the table of contents