X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Ffileref.c;h=716586c4a23c261e092a47f198d4ec6423669a8b;hb=1e0dc5378f314f555e3b923c6d95f5017abd528b;hp=3db89a2445cbcb204dc64709a75ff38a3f095540;hpb=c4142afddd5b220686eb64c4bd346a722f9e20c1;p=projects%2Fchimara%2Fchimara.git diff --git a/libchimara/fileref.c b/libchimara/fileref.c index 3db89a2..716586c 100644 --- a/libchimara/fileref.c +++ b/libchimara/fileref.c @@ -10,16 +10,17 @@ #include "chimara-glk-private.h" #include "gi_dispa.h" -extern GPrivate *glk_data_key; +extern GPrivate glk_data_key; -/* Internal function: create a fileref using the given parameters. */ +/* Internal function: create a fileref using the given parameters. If @basename +is NULL, compute a basename from @filename. */ frefid_t -fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode) +fileref_new(char *filename, char *basename, glui32 rock, glui32 usage, glui32 orig_filemode) { g_return_val_if_fail(filename != NULL, NULL); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); + frefid_t f = g_new0(struct glk_fileref_struct, 1); f->magic = MAGIC_FILEREF; f->rock = rock; @@ -27,6 +28,10 @@ fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode) f->disprock = (*glk_data->register_obj)(f, gidisp_Class_Fileref); f->filename = g_strdup(filename); + if(basename) + f->basename = g_strdup(basename); + else + f->basename = g_path_get_basename(filename); f->usage = usage; f->orig_filemode = orig_filemode; @@ -40,8 +45,8 @@ fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode) static void fileref_close_common(frefid_t fref) { - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); + glk_data->fileref_list = g_list_delete_link(glk_data->fileref_list, fref->fileref_list); if(glk_data->unregister_obj) @@ -50,8 +55,8 @@ fileref_close_common(frefid_t fref) fref->disprock.ptr = NULL; } - if(fref->filename) - g_free(fref->filename); + g_free(fref->filename); + g_free(fref->basename); fref->magic = MAGIC_FREE; g_free(fref); @@ -73,7 +78,7 @@ glk_fileref_iterate(frefid_t fref, glui32 *rockptr) { VALID_FILEREF_OR_NULL(fref, return NULL); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); GList *retnode; if(fref == NULL) @@ -147,7 +152,8 @@ glk_fileref_create_temp(glui32 usage, glui32 rock) return NULL; } - frefid_t f = fileref_new(filename, rock, usage, filemode_Write); + /* Pass a basename of "" to ensure that this file can't be repurposed */ + frefid_t f = fileref_new(filename, "", rock, usage, filemode_Write); g_free(filename); return f; } @@ -219,8 +225,8 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) for each usage */ GtkWidget *chooser; - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); + gdk_threads_enter(); switch(fmode) @@ -240,11 +246,7 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser), GTK_FILE_CHOOSER_ACTION_SAVE); - - /* COMPAT: */ -#if GTK_CHECK_VERSION(2,8,0) gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE); -#endif break; case filemode_ReadWrite: case filemode_WriteAppend: @@ -261,6 +263,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); @@ -271,7 +315,7 @@ glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock) return NULL; } gchar *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(chooser) ); - frefid_t f = fileref_new(filename, rock, usage, fmode); + frefid_t f = fileref_new(filename, NULL, rock, usage, fmode); g_free(filename); gtk_widget_destroy(chooser); @@ -388,11 +432,50 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) { g_return_val_if_fail(name != NULL && strlen(name) > 0, NULL); - ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); - + ChimaraGlkPrivate *glk_data = g_private_get(&glk_data_key); + /* Do any string-munging here to remove illegal Latin-1 characters from - filename. On ext3, the only illegal characters are '/' and '\0'. */ - g_strdelimit(name, "/", '_'); + filename. On ext3, the only illegal characters are '/' and '\0', but the Glk + spec calls for removing any other tricky characters. */ + char *buf = g_malloc(strlen(name)); + char *ptr, *filename, *extension; + int len; + for(ptr = name, len = 0; *ptr && *ptr != '.'; ptr++) + { + switch(*ptr) + { + case '"': case '\\': case '/': case '>': case '<': + case ':': case '|': case '?': case '*': + break; + default: + buf[len++] = *ptr; + } + } + buf[len] = '\0'; + + /* If there is nothing left, make the name "null" */ + if(len == 0) { + strcpy(buf, "null"); + len = strlen(buf); + } + + switch(usage & fileusage_TypeMask) + { + case fileusage_Data: + extension = ".glkdata"; + break; + case fileusage_SavedGame: + extension = ".glksave"; + break; + case fileusage_InputRecord: + case fileusage_Transcript: + extension = ".txt"; + break; + default: + ILLEGAL_PARAM("Unknown file usage: %u", usage); + return NULL; + } + filename = g_strconcat(buf, extension, NULL); /* Find out what encoding filenames are in */ const gchar **charsets; /* Do not free */ @@ -400,8 +483,7 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) /* Convert name to that encoding */ GError *error = NULL; - gchar *osname = g_convert(name, -1, charsets[0], "ISO-8859-1", NULL, NULL, - &error); + char *osname = g_convert(filename, -1, charsets[0], "ISO-8859-1", NULL, NULL, &error); if(osname == NULL) { WARNING_S("Error during latin1->filename conversion", error->message); @@ -415,8 +497,9 @@ glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock) path = g_strdup(osname); g_free(osname); - frefid_t f = fileref_new(path, rock, usage, filemode_ReadWrite); + frefid_t f = fileref_new(path, buf, rock, usage, filemode_ReadWrite); g_free(path); + g_free(buf); return f; } @@ -455,7 +538,7 @@ 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); + return fileref_new(fref->filename, fref->basename, rock, usage, fref->orig_filemode); } /**