X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=src%2Ffileref.c;h=2b5cf53efd65d9f8c04bc32732699e16c6db33a4;hb=91214934fbcdfd363202a65c142194506604ff7b;hp=be4f23f816aa1783c82f6419cef3d2da3168d73b;hpb=0d3a3e9d1aefbfb3d61b0ae98d543959874e4f78;p=projects%2Fchimara%2Fchimara.git diff --git a/src/fileref.c b/src/fileref.c index be4f23f..2b5cf53 100644 --- a/src/fileref.c +++ b/src/fileref.c @@ -1,32 +1,30 @@ +#include #include #include #include #include #include "fileref.h" +#include "magic.h" #include "chimara-glk-private.h" extern ChimaraGlkPrivate *glk_data; /** * glk_fileref_iterate: - * @fref: A file reference, or #NULL. - * @rockptr: Return location for the next window's rock, or #NULL. + * @fref: A file reference, or %NULL. + * @rockptr: Return location for the next fileref's rock, or %NULL. * - * Iterates over the list of file references; if @fref is #NULL, it returns the - * first file reference, otherwise the next file reference after @fref. If - * there are no more, it returns #NULL. The file reference's rock is stored in - * @rockptr. If you don't want the rocks to be returned, you may set @rockptr - * to #NULL. + * Iterates through all the existing filerefs. See Iterating Through Opaque + * Objects. * - * The order in which file references are returned is arbitrary. The order may - * change every time you create or destroy a file reference, invalidating the - * iteration. - * - * Returns: the next file reference, or #NULL if there are no more. + * Returns: the next file reference, or %NULL if there are no more. */ frefid_t glk_fileref_iterate(frefid_t fref, glui32 *rockptr) { + VALID_FILEREF_OR_NULL(fref, return NULL); + GList *retnode; if(fref == NULL) @@ -46,14 +44,15 @@ glk_fileref_iterate(frefid_t fref, glui32 *rockptr) * glk_fileref_get_rock: * @fref: A file reference. * - * Returns the file reference @fref's rock value. + * Retrieves the file reference @fref's rock value. See Rocks. * * Returns: A rock value. */ glui32 glk_fileref_get_rock(frefid_t fref) { - g_return_val_if_fail(fref != NULL, 0); + VALID_FILEREF(fref, return 0); return fref->rock; } @@ -64,6 +63,7 @@ fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode) g_return_val_if_fail(filename != NULL, NULL); frefid_t f = g_new0(struct glk_fileref_struct, 1); + f->magic = MAGIC_FILEREF; f->rock = rock; f->filename = g_strdup(filename); f->usage = usage; @@ -78,13 +78,17 @@ fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode) /** * glk_fileref_create_temp: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @rock: The new fileref's rock value. * * Creates a reference to a temporary file. It is always a new file (one which * does not yet exist). The file (once created) will be somewhere out of the * player's way. * + * + * This is why no name is specified; the player will never need to know it. + * + * * A temporary file should never be used for long-term storage. It may be * deleted automatically when the program exits, or at some later time, say * when the machine is turned off or rebooted. You do not have to worry about @@ -101,14 +105,14 @@ glk_fileref_create_temp(glui32 usage, glui32 rock) gint handle = g_file_open_tmp("glkXXXXXX", &filename, &error); if(handle == -1) { - g_warning("Error creating temporary file: %s", error->message); + WARNING_S("Error creating temporary file", error->message); if(filename) g_free(filename); return NULL; } - if(close(handle) == -1) /* There is no g_close()? */ + if(close(handle) == -1) /* There is no g_close() */ { - g_warning("Error closing temporary file."); + IO_WARNING( "Error closing temporary file", filename, g_strerror(errno) ); if(filename) g_free(filename); return NULL; @@ -121,18 +125,54 @@ glk_fileref_create_temp(glui32 usage, glui32 rock) /** * glk_fileref_create_by_prompt: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @fmode: File mode, contolling the dialog's behavior. * @rock: The new fileref's rock value. * - * Creates a reference to a file by opening a file chooser dialog. If @fmode is - * #filemode_Read, then the file must already exist and the user will be asked - * to select from existing files. If @fmode is #filemode_Write, then the file - * should not exist; if the user selects an existing file, he or she will be - * warned that it will be replaced. If @fmode is #filemode_ReadWrite, then the - * file may or may not exist; if it already exists, the user will be warned - * that it will be modified. The @fmode argument should generally match the - * @fmode which will be used to open the file. + * Creates a reference to a file by asking the player to locate it. The library + * may simply prompt the player to type a name, or may use a platform-native + * file navigation tool. (The prompt, if any, is inferred from the usage + * argument.) + * + * Chimara + * + * Chimara uses a GtkFileChooserDialog. + * + * + * @fmode must be one of these values: + * + * + * #filemode_Read + * The file must already exist; and the player will be asked + * to select from existing files which match the usage. + * + * + * #filemode_Write + * The file should not exist; if the player selects an + * existing file, he will be warned that it will be replaced. + * + * + * + * #filemode_ReadWrite + * The file may or may not exist; if it already exists, the + * player will be warned that it will be modified. + * + * + * #filemode_WriteAppend + * Same behavior as #filemode_ReadWrite. + * + * + * + * The @fmode argument should generally match the @fmode which will be used to + * open the file. + * + * + * It is possible that the prompt or file tool will have a + * cancel option. If the player chooses this, + * glk_fileref_create_by_prompt() will return %NULL. This is a major reason + * why you should make sure the return value is valid before you use it. + * * * Returns: A new fileref, or #NULL if the fileref creation failed or the * dialog was canceled. @@ -179,7 +219,7 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) GTK_FILE_CHOOSER_ACTION_SAVE); break; default: - g_warning("glk_fileref_create_by_prompt: Unsupported mode"); + ILLEGAL_PARAM("Unknown file mode: %u", fmode); gdk_threads_leave(); return NULL; } @@ -202,14 +242,42 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) /** * glk_fileref_create_by_name: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @name: A filename. * @rock: The new fileref's rock value. * * This creates a reference to a file with a specific name. The file will be - * in the same directory as your program, and visible to the player. + * in a fixed location relevant to your program, and visible to the player. + * + * + * This usually means in the same directory as your program. + * + * Chimara + * + * In Chimara, the file is created in the current working directory. + * + * + * Since filenames are highly platform-specific, you should use + * glk_fileref_create_by_name() with care. It is legal to pass any string in the + * name argument. However, the library may have to mangle, transform, or + * truncate the string to make it a legal native filename. * - * Returns: A new fileref, or #NULL if the fileref creation failed. + * + * For example, if you create two filerefs with the names File + * and FILE, they may wind up pointing to the same file; the + * platform may not support case distinctions in file names. Another example: + * on a platform where file type is specified by filename suffix, the library + * will add an appropriate suffix based on the usage; any suffix in the string + * will be overwritten or added to. For that matter, remember that the period + * is not a legal character in Acorn filenames... + * + * + * The most conservative approach is to pass a string of no more than 8 + * characters, consisting entirely of upper-case letters and numbers, starting + * with a letter. You can then be reasonably sure that the resulting filename + * will display all the characters you specify — in some form. + * + * Returns: A new fileref, or %NULL if the fileref creation failed. */ frefid_t glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) @@ -226,7 +294,7 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) &error); if(osname == NULL) { - g_warning("Error during latin1->filename conversion: %s", error->message); + WARNING_S("Error during latin1->filename conversion", error->message); return NULL; } @@ -242,21 +310,39 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) /** * glk_fileref_create_from_fileref: - * @usage: Bitfield with one or more of the #fileusage_ constants. + * @usage: Bitfield with one or more of the fileusage_ constants. * @fref: Fileref to copy. * @rock: The new fileref's rock value. * * This copies an existing file reference @fref, but changes the usage. (The - * original @fref is not modified.) + * original fileref is not modified.) + * + * The use of this function can be tricky. If you change the type of the fileref + * (#fileusage_Data, #fileusage_SavedGame, etc), the new reference may or may + * not point to the same actual disk file. + * + * + * This generally depends on whether the platform uses suffixes to indicate + * file type. + * * - * If you write to a file in text mode and then read from it in binary mode, - * the results are platform-dependent. + * If you do this, and open both file references for writing, the results are + * unpredictable. It is safest to change the type of a fileref only if it refers + * to a nonexistent file. * - * Returns: A new fileref, or #NULL if the fileref creation failed. + * If you change the mode of a fileref (#fileusage_TextMode, + * #fileusage_BinaryMode), but leave the rest of the type unchanged, the new + * fileref will definitely point to the same disk file as the old one. + * + * Obviously, if you write to a file in text mode and then read from it in + * binary mode, the results are platform-dependent. + * + * Returns: A new fileref, or %NULL if the fileref creation failed. */ frefid_t glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock) { + VALID_FILEREF(fref, return NULL); return fileref_new(fref->filename, rock, usage, fref->orig_filemode); } @@ -264,8 +350,9 @@ glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock) * glk_fileref_destroy: * @fref: Fileref to destroy. * - * Destroys a fileref which you have created. This does not affect the disk - * file. + * Destroys a fileref which you have created. This does not + * affect the disk file; it just reclaims the resources allocated by the + * glk_fileref_create... function. * * It is legal to destroy a fileref after opening a file with it (while the * file is still open.) The fileref is only used for the opening operation, @@ -274,9 +361,13 @@ glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock) void glk_fileref_destroy(frefid_t fref) { + VALID_FILEREF(fref, return); + glk_data->fileref_list = g_list_delete_link(glk_data->fileref_list, fref->fileref_list); if(fref->filename) g_free(fref->filename); + + fref->magic = MAGIC_FREE; g_free(fref); } @@ -284,14 +375,15 @@ glk_fileref_destroy(frefid_t fref) * glk_fileref_delete_file: * @fref: A refrence to the file to delete. * - * Deletes the file referred to by @fref. Does not destroy @fref itself. + * Deletes the file referred to by @fref. It does not destroy @fref itself. */ void glk_fileref_delete_file(frefid_t fref) { + VALID_FILEREF(fref, return); if( glk_fileref_does_file_exist(fref) ) if(g_unlink(fref->filename) == -1) - g_warning("Error deleting file %s", fref->filename); + IO_WARNING( "Error deleting file", fref->filename, g_strerror(errno) ); } /** @@ -300,11 +392,13 @@ glk_fileref_delete_file(frefid_t fref) * * Checks whether the file referred to by @fref exists. * - * Returns: #TRUE (1) if @fref refers to an existing file, #FALSE (0) if not. + * Returns: %TRUE (1) if @fref refers to an existing file, and %FALSE (0) if + * not. */ glui32 glk_fileref_does_file_exist(frefid_t fref) { + VALID_FILEREF(fref, return 0); if( g_file_test(fref->filename, G_FILE_TEST_EXISTS) ) return 1; return 0;