Use statically-allocated thread private data
[projects/chimara/chimara.git] / libchimara / fileref.c
index 8bda95f8a9a90765685f1c42f722885dbf3be0d9..716586c4a23c261e092a47f198d4ec6423669a8b 100644 (file)
 #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:
@@ -313,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);
 
@@ -430,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 */
@@ -442,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);
@@ -457,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;
 }
 
@@ -497,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);
 }
 
 /**