X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Ffileref.c;h=8bda95f8a9a90765685f1c42f722885dbf3be0d9;hb=3235a688697a3b015988a5312aed9116f6f8aa59;hp=d0cee0829479ecded8a6ec5b743a5298c4cf3c60;hpb=40cf50b43f824311d7f14893ed1193bb5642741a;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/fileref.c b/libchimara/fileref.c index d0cee08..8bda95f 100644 --- a/libchimara/fileref.c +++ b/libchimara/fileref.c @@ -1,8 +1,10 @@ +#include #include #include #include #include #include +#include #include "fileref.h" #include "magic.h" #include "chimara-glk-private.h" @@ -164,7 +166,7 @@ glk_fileref_create_temp(glui32 usage, glui32 rock) * Chimara * * Chimara uses a GtkFileChooserDialog. The default + * linkend="GtkFileChooserDialog">GtkFileChooserDialog. The default * starting location for the dialog may be set with glkunix_set_base_file(). * * @@ -196,12 +198,17 @@ glk_fileref_create_temp(glui32 usage, glui32 rock) * 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. + * It is likely 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. * * + * The recommended file suffixes for files are .glkdata for + * %fileusage_Data, .glksave for %fileusage_SavedGame, + * .txt for %fileusage_Transcript and + * %fileusage_InputRecord. + * * Returns: A new fileref, or #NULL if the fileref creation failed or the * dialog was canceled. */ @@ -254,6 +261,48 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) return NULL; } + /* Set up a file filter with suggested extensions */ + GtkFileFilter *filter = gtk_file_filter_new(); + switch(usage & fileusage_TypeMask) + { + case fileusage_Data: + gtk_file_filter_set_name(filter, _("Data files (*.glkdata)")); + gtk_file_filter_add_pattern(filter, "*.glkdata"); + break; + case fileusage_SavedGame: + gtk_file_filter_set_name(filter, _("Saved games (*.glksave)")); + gtk_file_filter_add_pattern(filter, "*.glksave"); + break; + case fileusage_InputRecord: + gtk_file_filter_set_name(filter, _("Text files (*.txt)")); + gtk_file_filter_add_pattern(filter, "*.txt"); + break; + case fileusage_Transcript: + gtk_file_filter_set_name(filter, _("Transcript files (*.txt)")); + gtk_file_filter_add_pattern(filter, "*.txt"); + break; + default: + ILLEGAL_PARAM("Unknown file usage: %u", usage); + gdk_threads_leave(); + return NULL; + } + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter); + + /* Add a "text mode" filter for text files */ + if((usage & fileusage_TypeMask) == fileusage_InputRecord || (usage & fileusage_TypeMask) == fileusage_Transcript) + { + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, _("All text files")); + gtk_file_filter_add_mime_type(filter, "text/plain"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter); + } + + /* Add another non-restricted filter */ + filter = gtk_file_filter_new(); + gtk_file_filter_set_name(filter, _("All files")); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter); + if(glk_data->current_dir) gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), glk_data->current_dir); @@ -290,25 +339,89 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) * glkunix_set_base_file(), and otherwise 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. + * 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 consensus 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. + * + * The above behavior is not a requirement of the Glk spec. Older + * implementations can continue doing what they do. Some programs (e.g. + * web-based interpreters) may not have access to a traditional filesystem at + * all, and to them these recommendations will be meaningless. + * + * On the other side of the coin, the game file should not press these + * limitations. Best practice is for the game to pass a filename containing only + * letters and digits, beginning with a letter, and not mixing upper and lower + * case. Avoid overly-long filenames. * * - * 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 earlier Glk spec gave more stringent recommendations: No more + * than 8 characters, consisting entirely of upper-case letters and numbers, + * starting with a letter. The DOS era is safely contained, if not + * over, so this has been relaxed. The I7 manual recommends 23 + * characters or fewer. * * - * 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. + * + * To address other complications: + * + * + * Some filesystems are case-insensitive. If you create two filerefs with + * the names File and FILE, they + * may wind up pointing to the same file, or they may not. Avoid doing + * this. + * + * + * Some programs will look for all files in the same directory as the + * program itself (or, for interpreted games, in the same directory as the + * game file). Others may keep files in a data-specific directory + * appropriate for the user (e.g., ~/Library on MacOS). + * + * + * If a game interpreter uses a data-specific directory, there is a + * question of whether to use a common location, or divide it into + * game-specific subdirectories. (Or to put it another way: should the + * namespace of named files be per-game or app-wide?) Since data files may + * be exchanged between games, they should be given an app-wide namespace. + * In contrast, saved games should be per-game, as they can never be + * exchanged. Transcripts and input records can go either way. + * + * + * When updating an older library to follow these recommendations, + * consider backwards compatibility for games already installed. When + * opening an existing file (that is, not in a write-only mode) it may be + * worth looking under the older name (suffix) if the newer one does not + * already exist. + * + * + * Game-save files are already stored with a variety of file suffixes, + * since that usage goes back to the oldest IF interpreters, long + * predating Glk. It is reasonable to treat them in some special way, + * while hewing closer to these recommendations for data files. + * + * + * * * Returns: A new fileref, or %NULL if the fileref creation failed. */ @@ -363,8 +476,8 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) * not point to the same actual disk file. * * - * This generally depends on whether the platform uses suffixes to indicate - * file type. + * Most platforms use suffixes to indicate file type, so it typically will + * not. See the earlier comments about recommended file suffixes. * * * If you do this, and open both file references for writing, the results are @@ -411,14 +524,23 @@ glk_fileref_destroy(frefid_t fref) * @fref: A refrence to the file to delete. * * Deletes the file referred to by @fref. It does not destroy @fref itself. + * + * You should only call this with a fileref that refers to an existing file. */ 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) IO_WARNING( "Error deleting file", fref->filename, g_strerror(errno) ); + } + else + { + ILLEGAL(_("Tried to delete a fileref that does not refer to an existing file.")); + } + } /**