6 #include <glib/gstdio.h>
7 #include <glib/gi18n-lib.h>
10 #include "chimara-glk-private.h"
13 extern GPrivate *glk_data_key;
15 /* Internal function: create a fileref using the given parameters. */
17 fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode)
19 g_return_val_if_fail(filename != NULL, NULL);
21 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
23 frefid_t f = g_new0(struct glk_fileref_struct, 1);
24 f->magic = MAGIC_FILEREF;
26 if(glk_data->register_obj)
27 f->disprock = (*glk_data->register_obj)(f, gidisp_Class_Fileref);
29 f->filename = g_strdup(filename);
31 f->orig_filemode = orig_filemode;
33 /* Add it to the global fileref list */
34 glk_data->fileref_list = g_list_prepend(glk_data->fileref_list, f);
35 f->fileref_list = glk_data->fileref_list;
41 fileref_close_common(frefid_t fref)
43 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
45 glk_data->fileref_list = g_list_delete_link(glk_data->fileref_list, fref->fileref_list);
47 if(glk_data->unregister_obj)
49 (*glk_data->unregister_obj)(fref, gidisp_Class_Fileref, fref->disprock);
50 fref->disprock.ptr = NULL;
54 g_free(fref->filename);
56 fref->magic = MAGIC_FREE;
61 * glk_fileref_iterate:
62 * @fref: A file reference, or %NULL.
63 * @rockptr: Return location for the next fileref's rock, or %NULL.
65 * Iterates through all the existing filerefs. See <link
66 * linkend="chimara-Iterating-Through-Opaque-Objects">Iterating Through Opaque
69 * Returns: the next file reference, or %NULL if there are no more.
72 glk_fileref_iterate(frefid_t fref, glui32 *rockptr)
74 VALID_FILEREF_OR_NULL(fref, return NULL);
76 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
80 retnode = glk_data->fileref_list;
82 retnode = fref->fileref_list->next;
83 frefid_t retval = retnode? (frefid_t)retnode->data : NULL;
85 /* Store the fileref's rock in rockptr */
87 *rockptr = glk_fileref_get_rock(retval);
93 * glk_fileref_get_rock:
94 * @fref: A file reference.
96 * Retrieves the file reference @fref's rock value. See <link
97 * linkend="chimara-Rocks">Rocks</link>.
99 * Returns: A rock value.
102 glk_fileref_get_rock(frefid_t fref)
104 VALID_FILEREF(fref, return 0);
109 * glk_fileref_create_temp:
110 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
111 * @rock: The new fileref's rock value.
113 * Creates a reference to a temporary file. It is always a new file (one which
114 * does not yet exist). The file (once created) will be somewhere out of the
118 * This is why no name is specified; the player will never need to know it.
121 * A temporary file should never be used for long-term storage. It may be
122 * deleted automatically when the program exits, or at some later time, say
123 * when the machine is turned off or rebooted. You do not have to worry about
124 * deleting it yourself.
126 * Returns: A new fileref, or #NULL if the fileref creation failed.
129 glk_fileref_create_temp(glui32 usage, glui32 rock)
131 /* Get a temp file */
132 GError *error = NULL;
133 gchar *filename = NULL;
134 gint handle = g_file_open_tmp("glkXXXXXX", &filename, &error);
137 WARNING_S("Error creating temporary file", error->message);
142 if(close(handle) == -1) /* There is no g_close() */
144 IO_WARNING( "Error closing temporary file", filename, g_strerror(errno) );
150 frefid_t f = fileref_new(filename, rock, usage, filemode_Write);
156 * glk_fileref_create_by_prompt:
157 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
158 * @fmode: File mode, contolling the dialog's behavior.
159 * @rock: The new fileref's rock value.
161 * Creates a reference to a file by asking the player to locate it. The library
162 * may simply prompt the player to type a name, or may use a platform-native
163 * file navigation tool. (The prompt, if any, is inferred from the usage
166 * <note><title>Chimara</title>
168 * Chimara uses a <link
169 * linkend="GtkFileChooserDialog">GtkFileChooserDialog</link>. The default
170 * starting location for the dialog may be set with glkunix_set_base_file().
173 * @fmode must be one of these values:
176 * <term>%filemode_Read</term>
177 * <listitem><para>The file must already exist; and the player will be asked
178 * to select from existing files which match the usage.</para></listitem>
181 * <term>%filemode_Write</term>
182 * <listitem><para>The file should not exist; if the player selects an
183 * existing file, he will be warned that it will be replaced.
187 * <term>%filemode_ReadWrite</term>
188 * <listitem><para>The file may or may not exist; if it already exists, the
189 * player will be warned that it will be modified.</para></listitem>
192 * <term>%filemode_WriteAppend</term>
193 * <listitem><para>Same behavior as %filemode_ReadWrite.</para></listitem>
197 * The @fmode argument should generally match the @fmode which will be used to
201 * It is likely that the prompt or file tool will have a <quote>cancel</quote>
202 * option. If the player chooses this, glk_fileref_create_by_prompt() will
203 * return %NULL. This is a major reason why you should make sure the return
204 * value is valid before you use it.
207 * Returns: A new fileref, or #NULL if the fileref creation failed or the
208 * dialog was canceled.
211 glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock)
213 /* TODO: Remember current working directory and last used filename
217 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
224 chooser = gtk_file_chooser_dialog_new("Select a file to open", NULL,
225 GTK_FILE_CHOOSER_ACTION_OPEN,
226 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
227 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
229 gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser), GTK_FILE_CHOOSER_ACTION_OPEN);
232 chooser = gtk_file_chooser_dialog_new("Select a file to save to", NULL,
233 GTK_FILE_CHOOSER_ACTION_SAVE,
234 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
235 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
237 gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser), GTK_FILE_CHOOSER_ACTION_SAVE);
240 #if GTK_CHECK_VERSION(2,8,0)
241 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(chooser), TRUE);
244 case filemode_ReadWrite:
245 case filemode_WriteAppend:
246 chooser = gtk_file_chooser_dialog_new("Select a file to save to", NULL,
247 GTK_FILE_CHOOSER_ACTION_SAVE,
248 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
249 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
251 gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser), GTK_FILE_CHOOSER_ACTION_SAVE);
254 ILLEGAL_PARAM("Unknown file mode: %u", fmode);
259 if(glk_data->current_dir)
260 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), glk_data->current_dir);
262 if(gtk_dialog_run( GTK_DIALOG(chooser) ) != GTK_RESPONSE_ACCEPT)
264 gtk_widget_destroy(chooser);
268 gchar *filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(chooser) );
269 frefid_t f = fileref_new(filename, rock, usage, fmode);
271 gtk_widget_destroy(chooser);
278 * glk_fileref_create_by_name:
279 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
281 * @rock: The new fileref's rock value.
283 * This creates a reference to a file with a specific name. The file will be
284 * in a fixed location relevant to your program, and visible to the player.
287 * This usually means <quote>in the same directory as your program.</quote>
289 * <note><title>Chimara</title>
291 * In Chimara, the file is created in the directory last set by
292 * glkunix_set_base_file(), and otherwise in the current working directory.
295 * Since filenames are highly platform-specific, you should use
296 * glk_fileref_create_by_name() with care. It is legal to pass any string in the
297 * name argument. However, the library may have to mangle, transform, or
298 * truncate the string to make it a legal native filename.
301 * For example, if you create two filerefs with the names <quote>File</quote>
302 * and <quote>FILE</quote>, they may wind up pointing to the same file; the
303 * platform may not support case distinctions in file names. Another example:
304 * on a platform where file type is specified by filename suffix, the library
305 * will add an appropriate suffix based on the usage; any suffix in the string
306 * will be overwritten or added to. For that matter, remember that the period
307 * is not a legal character in Acorn filenames...
310 * The most conservative approach is to pass a string of no more than 8
311 * characters, consisting entirely of upper-case letters and numbers, starting
312 * with a letter. You can then be reasonably sure that the resulting filename
313 * will display all the characters you specify — in some form.
315 * Returns: A new fileref, or %NULL if the fileref creation failed.
318 glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock)
320 g_return_val_if_fail(name != NULL && strlen(name) > 0, NULL);
322 ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key);
324 /* Do any string-munging here to remove illegal Latin-1 characters from
325 filename. On ext3, the only illegal characters are '/' and '\0'. */
326 g_strdelimit(name, "/", '_');
328 /* Find out what encoding filenames are in */
329 const gchar **charsets; /* Do not free */
330 g_get_filename_charsets(&charsets);
332 /* Convert name to that encoding */
333 GError *error = NULL;
334 gchar *osname = g_convert(name, -1, charsets[0], "ISO-8859-1", NULL, NULL,
338 WARNING_S("Error during latin1->filename conversion", error->message);
343 if(glk_data->current_dir)
344 path = g_build_filename(glk_data->current_dir, osname, NULL);
346 path = g_strdup(osname);
349 frefid_t f = fileref_new(path, rock, usage, filemode_ReadWrite);
355 * glk_fileref_create_from_fileref:
356 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
357 * @fref: Fileref to copy.
358 * @rock: The new fileref's rock value.
360 * This copies an existing file reference @fref, but changes the usage. (The
361 * original fileref is not modified.)
363 * The use of this function can be tricky. If you change the type of the fileref
364 * (%fileusage_Data, %fileusage_SavedGame, etc), the new reference may or may
365 * not point to the same actual disk file.
368 * This generally depends on whether the platform uses suffixes to indicate
372 * If you do this, and open both file references for writing, the results are
373 * unpredictable. It is safest to change the type of a fileref only if it refers
374 * to a nonexistent file.
376 * If you change the mode of a fileref (%fileusage_TextMode,
377 * %fileusage_BinaryMode), but leave the rest of the type unchanged, the new
378 * fileref will definitely point to the same disk file as the old one.
380 * Obviously, if you write to a file in text mode and then read from it in
381 * binary mode, the results are platform-dependent.
383 * Returns: A new fileref, or %NULL if the fileref creation failed.
386 glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock)
388 VALID_FILEREF(fref, return NULL);
389 return fileref_new(fref->filename, rock, usage, fref->orig_filemode);
393 * glk_fileref_destroy:
394 * @fref: Fileref to destroy.
396 * Destroys a fileref which you have created. This does <emphasis>not</emphasis>
397 * affect the disk file; it just reclaims the resources allocated by the
398 * <code>glk_fileref_create...</code> function.
400 * It is legal to destroy a fileref after opening a file with it (while the
401 * file is still open.) The fileref is only used for the opening operation,
402 * not for accessing the file stream.
405 glk_fileref_destroy(frefid_t fref)
407 VALID_FILEREF(fref, return);
408 fileref_close_common(fref);
412 * glk_fileref_delete_file:
413 * @fref: A refrence to the file to delete.
415 * Deletes the file referred to by @fref. It does not destroy @fref itself.
417 * You should only call this with a fileref that refers to an existing file.
420 glk_fileref_delete_file(frefid_t fref)
422 VALID_FILEREF(fref, return);
423 if( glk_fileref_does_file_exist(fref) )
425 if(g_unlink(fref->filename) == -1)
426 IO_WARNING( "Error deleting file", fref->filename, g_strerror(errno) );
430 ILLEGAL(_("Tried to delete a fileref that does not refer to an existing file."));
436 * glk_fileref_does_file_exist:
437 * @fref: A fileref to check.
439 * Checks whether the file referred to by @fref exists.
441 * Returns: %TRUE (1) if @fref refers to an existing file, and %FALSE (0) if
445 glk_fileref_does_file_exist(frefid_t fref)
447 VALID_FILEREF(fref, return 0);
448 if( g_file_test(fref->filename, G_FILE_TEST_EXISTS) )