From 4a8f20f28d17b8995a8770cc7ef95db3cb5212b4 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Sun, 20 Jul 2008 00:09:16 +0000 Subject: [PATCH] All of the fileref functions are now implemented: glk_fileref_create_temp() glk_fileref_create_by_prompt() glk_fileref_create_by_name() glk_fileref_create_from_fileref() glk_fileref_destroy() glk_fileref_delete_file() glk_fileref_does_file_exist() git-svn-id: http://lassie.dyndns-server.com/svn/gargoyle-gtk@6 ddfedd41-794f-dd11-ae45-00112f111e67 --- src/fileref.c | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/fileref.h | 6 +- src/model.c | 7 ++ 3 files changed, 255 insertions(+), 2 deletions(-) diff --git a/src/fileref.c b/src/fileref.c index 678a9be..b277bb3 100644 --- a/src/fileref.c +++ b/src/fileref.c @@ -1,4 +1,9 @@ +#include +#include +#include +#include #include "fileref.h" +#include "error.h" /* List of streams currently in existence */ static GList *fileref_list = NULL; @@ -52,3 +57,242 @@ glk_fileref_get_rock(frefid_t fref) g_return_val_if_fail(fref != NULL, 0); return fref->rock; } + +/* Internal function: create a fileref using the given parameters. */ +static frefid_t +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->rock = rock; + f->filename = g_strdup(filename); + f->usage = usage; + f->orig_filemode = orig_filemode; + + /* Add it to the global fileref list */ + fileref_list = g_list_prepend(fileref_list, f); + f->fileref_list = fileref_list; + + return f; +} + +/** + * glk_fileref_create_temp: + * @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. + * + * 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 + * deleting it yourself. + * + * Returns: A new fileref, or #NULL if the fileref creation failed. + */ +frefid_t +glk_fileref_create_temp(glui32 usage, glui32 rock) +{ + /* Get a temp file */ + GError *error = NULL; + gchar *filename = NULL; + gint handle = g_file_open_tmp("glkXXXXXX", &filename, &error); + if(handle == -1) + { + error_dialog(NULL, error, "Error creating temporary file: "); + if(filename) + g_free(filename); + return NULL; + } + if(close(handle) == -1) /* There is no g_close()? */ + { + error_dialog(NULL, NULL, "Error closing temporary file."); + if(filename) + g_free(filename); + return NULL; + } + + frefid_t f = fileref_new(filename, rock, usage, filemode_Write); + g_free(filename); + return f; +} + +/** + * glk_fileref_create_by_prompt: + * @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. + * + * Returns: A new fileref, or #NULL if the fileref creation failed or the + * dialog was canceled. + */ +frefid_t +glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) +{ + /* TODO: Remember current working directory and last used filename + for each usage */ + GtkWidget *chooser; + switch(fmode) + { + case filemode_Read: + chooser = gtk_file_chooser_dialog_new("Select a file", NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser), + GTK_FILE_CHOOSER_ACTION_OPEN); + break; + case filemode_Write: + case filemode_ReadWrite: + case filemode_WriteAppend: + chooser = gtk_file_chooser_dialog_new("Select a file", NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser), + GTK_FILE_CHOOSER_ACTION_SAVE); + gtk_file_chooser_set_do_overwrite_confirmation( + GTK_FILE_CHOOSER(chooser), TRUE); + break; + default: + g_warning("glk_fileref_create_by_prompt: Unsupported mode"); + return NULL; + } + + if(gtk_dialog_run( GTK_DIALOG(chooser) ) != GTK_RESPONSE_ACCEPT) + { + gtk_widget_destroy(chooser); + return NULL; + } + gchar *filename = + gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(chooser) ); + frefid_t f = fileref_new(filename, rock, usage, fmode); + g_free(filename); + gtk_widget_destroy(chooser); + return f; +} + +/** + * glk_fileref_create_by_name: + * @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. + * + * Returns: A new fileref, or #NULL if the fileref creation failed. + */ +frefid_t +glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) +{ + g_return_val_if_fail(name != NULL && strlen(name) > 0, NULL); + + /* Find out what encoding filenames are in */ + const gchar **charsets; /* Do not free */ + g_get_filename_charsets(&charsets); + + /* Convert name to that encoding */ + GError *error = NULL; + gchar *osname = g_convert(name, -1, charsets[0], "ISO-8859-1", NULL, NULL, + &error); + if(osname == NULL) + { + error_dialog(NULL, error, "Error during latin1->filename conversion: "); + return NULL; + } + + /* Do any string-munging here to remove illegal characters from filename. + On ext3, the only illegal characters are '/' and '\0'. TODO: Should this + function be allowed to reference files in other directories, or should we + disallow '/'? */ + + frefid_t f = fileref_new(osname, rock, usage, filemode_ReadWrite); + g_free(osname); + return f; +} + +/** + * glk_fileref_create_from_fileref: + * @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.) + * + * 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) +{ + return fileref_new(fref->filename, rock, usage, fref->orig_filemode); +} + +/** + * glk_fileref_destroy: + * @fref: Fileref to destroy. + * + * Destroys a fileref which you have created. This does not affect the disk + * file. + * + * 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, + * not for accessing the file stream. + */ +void +glk_fileref_destroy(frefid_t fref) +{ + fileref_list = g_list_delete_link(fileref_list, fref->fileref_list); + if(fref->filename) + g_free(fref->filename); + g_free(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. + */ +void +glk_fileref_delete_file(frefid_t fref) +{ + if( glk_fileref_does_file_exist(fref) ) + if(g_unlink(fref->filename) == -1) + error_dialog(NULL, NULL, "Error deleting file %s", fref->filename); +} + +/** + * glk_fileref_does_file_exist: + * @fref: A fileref to check. + * + * Checks whether the file referred to by @fref exists. + * + * Returns: #TRUE (1) if @fref refers to an existing file, #FALSE (0) if not. + */ +glui32 +glk_fileref_does_file_exist(frefid_t fref) +{ + if( g_file_test(fref->filename, G_FILE_TEST_EXISTS) ) + return 1; + return 0; +} + diff --git a/src/fileref.h b/src/fileref.h index fb52ee5..6dcefed 100644 --- a/src/fileref.h +++ b/src/fileref.h @@ -11,8 +11,10 @@ struct glk_fileref_struct fileref */ GList* fileref_list; /* Fileref parameters */ - gchar *filename; - glui32 filemode; + gchar *filename; /* Always stored in the default filename encoding, not + UTF8 or Latin-1 */ + glui32 orig_filemode; /* Used to check if the user gets a fileref in read + mode and then tries to open it in write mode */ glui32 usage; }; diff --git a/src/model.c b/src/model.c index 10bafb7..2de9f9b 100644 --- a/src/model.c +++ b/src/model.c @@ -22,6 +22,13 @@ void glk_main(void) glk_put_string("Philip en Marijn zijn vet goed.\n"); glk_put_string(buffer); + + frefid_t f = glk_fileref_create_by_prompt(fileusage_TextMode, filemode_Write, 0); + if( glk_fileref_does_file_exist(f) ) + glk_put_string("\n\nFile exists!\n"); + else + glk_put_string("\n\nFile does not exist!\n"); + glk_fileref_destroy(f); /* Bye bye */ glk_exit(); -- 2.30.2