4 #include <glib/gstdio.h>
6 #include "chimara-glk-private.h"
8 extern ChimaraGlkPrivate *glk_data;
11 * glk_fileref_iterate:
12 * @fref: A file reference, or %NULL.
13 * @rockptr: Return location for the next fileref's rock, or %NULL.
15 * Iterates through all the existing filerefs. See <link
16 * linkend="chimara-Iterating-Through-Opaque-Objects">Iterating Through Opaque
19 * Returns: the next file reference, or %NULL if there are no more.
22 glk_fileref_iterate(frefid_t fref, glui32 *rockptr)
27 retnode = glk_data->fileref_list;
29 retnode = fref->fileref_list->next;
30 frefid_t retval = retnode? (frefid_t)retnode->data : NULL;
32 /* Store the fileref's rock in rockptr */
34 *rockptr = glk_fileref_get_rock(retval);
40 * glk_fileref_get_rock:
41 * @fref: A file reference.
43 * Retrieves the file reference @fref's rock value. See <link
44 * linkend="chimara-Rocks">Rocks</link>.
46 * Returns: A rock value.
49 glk_fileref_get_rock(frefid_t fref)
51 g_return_val_if_fail(fref != NULL, 0);
55 /* Internal function: create a fileref using the given parameters. */
57 fileref_new(gchar *filename, glui32 rock, glui32 usage, glui32 orig_filemode)
59 g_return_val_if_fail(filename != NULL, NULL);
61 frefid_t f = g_new0(struct glk_fileref_struct, 1);
63 f->filename = g_strdup(filename);
65 f->orig_filemode = orig_filemode;
67 /* Add it to the global fileref list */
68 glk_data->fileref_list = g_list_prepend(glk_data->fileref_list, f);
69 f->fileref_list = glk_data->fileref_list;
75 * glk_fileref_create_temp:
76 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
77 * @rock: The new fileref's rock value.
79 * Creates a reference to a temporary file. It is always a new file (one which
80 * does not yet exist). The file (once created) will be somewhere out of the
84 * This is why no name is specified; the player will never need to know it.
87 * A temporary file should never be used for long-term storage. It may be
88 * deleted automatically when the program exits, or at some later time, say
89 * when the machine is turned off or rebooted. You do not have to worry about
90 * deleting it yourself.
92 * Returns: A new fileref, or #NULL if the fileref creation failed.
95 glk_fileref_create_temp(glui32 usage, glui32 rock)
99 gchar *filename = NULL;
100 gint handle = g_file_open_tmp("glkXXXXXX", &filename, &error);
103 g_warning("Error creating temporary file: %s", error->message);
108 if(close(handle) == -1) /* There is no g_close()? */
110 g_warning("Error closing temporary file.");
116 frefid_t f = fileref_new(filename, rock, usage, filemode_Write);
122 * glk_fileref_create_by_prompt:
123 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
124 * @fmode: File mode, contolling the dialog's behavior.
125 * @rock: The new fileref's rock value.
127 * Creates a reference to a file by asking the player to locate it. The library
128 * may simply prompt the player to type a name, or may use a platform-native
129 * file navigation tool. (The prompt, if any, is inferred from the usage
132 * <note><title>Chimara</title>
134 * Chimara uses a <link
135 * linkend="gtk-GtkFileChooserDialog">GtkFileChooserDialog</link>.
138 * @fmode must be one of these values:
141 * <term>#filemode_Read</term>
142 * <listitem><para>The file must already exist; and the player will be asked
143 * to select from existing files which match the usage.</para></listitem>
146 * <term>#filemode_Write</term>
147 * <listitem><para>The file should not exist; if the player selects an
148 * existing file, he will be warned that it will be replaced.
152 * <term>#filemode_ReadWrite</term>
153 * <listitem><para>The file may or may not exist; if it already exists, the
154 * player will be warned that it will be modified.</para></listitem>
157 * <term>#filemode_WriteAppend</term>
158 * <listitem><para>Same behavior as #filemode_ReadWrite.</para></listitem>
162 * The @fmode argument should generally match the @fmode which will be used to
166 * It is possible that the prompt or file tool will have a
167 * <quote>cancel</quote> option. If the player chooses this,
168 * glk_fileref_create_by_prompt() will return %NULL. This is a major reason
169 * why you should make sure the return value is valid before you use it.
172 * Returns: A new fileref, or #NULL if the fileref creation failed or the
173 * dialog was canceled.
176 glk_fileref_create_by_prompt(glui32 usage, glui32 fmode, glui32 rock)
178 /* TODO: Remember current working directory and last used filename
187 chooser = gtk_file_chooser_dialog_new("Select a file to open", NULL,
188 GTK_FILE_CHOOSER_ACTION_OPEN,
189 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
190 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
192 gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser),
193 GTK_FILE_CHOOSER_ACTION_OPEN);
196 chooser = gtk_file_chooser_dialog_new("Select a file to save to", NULL,
197 GTK_FILE_CHOOSER_ACTION_SAVE,
198 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
199 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
201 gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser),
202 GTK_FILE_CHOOSER_ACTION_SAVE);
203 gtk_file_chooser_set_do_overwrite_confirmation(
204 GTK_FILE_CHOOSER(chooser), TRUE);
206 case filemode_ReadWrite:
207 case filemode_WriteAppend:
208 chooser = gtk_file_chooser_dialog_new("Select a file to save to", NULL,
209 GTK_FILE_CHOOSER_ACTION_SAVE,
210 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
211 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
213 gtk_file_chooser_set_action(GTK_FILE_CHOOSER(chooser),
214 GTK_FILE_CHOOSER_ACTION_SAVE);
217 g_warning("glk_fileref_create_by_prompt: Unsupported mode");
222 if(gtk_dialog_run( GTK_DIALOG(chooser) ) != GTK_RESPONSE_ACCEPT)
224 gtk_widget_destroy(chooser);
229 gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(chooser) );
230 frefid_t f = fileref_new(filename, rock, usage, fmode);
232 gtk_widget_destroy(chooser);
239 * glk_fileref_create_by_name:
240 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
242 * @rock: The new fileref's rock value.
244 * This creates a reference to a file with a specific name. The file will be
245 * in a fixed location relevant to your program, and visible to the player.
248 * This usually means <quote>in the same directory as your program.</quote>
250 * <note><title>Chimara</title>
252 * In Chimara, the file is created in the current working directory.
255 * Since filenames are highly platform-specific, you should use
256 * glk_fileref_create_by_name() with care. It is legal to pass any string in the
257 * name argument. However, the library may have to mangle, transform, or
258 * truncate the string to make it a legal native filename.
261 * For example, if you create two filerefs with the names <quote>File</quote>
262 * and <quote>FILE</quote>, they may wind up pointing to the same file; the
263 * platform may not support case distinctions in file names. Another example:
264 * on a platform where file type is specified by filename suffix, the library
265 * will add an appropriate suffix based on the usage; any suffix in the string
266 * will be overwritten or added to. For that matter, remember that the period
267 * is not a legal character in Acorn filenames...
270 * The most conservative approach is to pass a string of no more than 8
271 * characters, consisting entirely of upper-case letters and numbers, starting
272 * with a letter. You can then be reasonably sure that the resulting filename
273 * will display all the characters you specify — in some form.
275 * Returns: A new fileref, or %NULL if the fileref creation failed.
278 glk_fileref_create_by_name(glui32 usage, char *name, glui32 rock)
280 g_return_val_if_fail(name != NULL && strlen(name) > 0, NULL);
282 /* Find out what encoding filenames are in */
283 const gchar **charsets; /* Do not free */
284 g_get_filename_charsets(&charsets);
286 /* Convert name to that encoding */
287 GError *error = NULL;
288 gchar *osname = g_convert(name, -1, charsets[0], "ISO-8859-1", NULL, NULL,
292 g_warning("Error during latin1->filename conversion: %s", error->message);
296 /* Do any string-munging here to remove illegal characters from filename.
297 On ext3, the only illegal characters are '/' and '\0'. TODO: Should this
298 function be allowed to reference files in other directories, or should we
301 frefid_t f = fileref_new(osname, rock, usage, filemode_ReadWrite);
307 * glk_fileref_create_from_fileref:
308 * @usage: Bitfield with one or more of the <code>fileusage_</code> constants.
309 * @fref: Fileref to copy.
310 * @rock: The new fileref's rock value.
312 * This copies an existing file reference @fref, but changes the usage. (The
313 * original fileref is not modified.)
315 * The use of this function can be tricky. If you change the type of the fileref
316 * (#fileusage_Data, #fileusage_SavedGame, etc), the new reference may or may
317 * not point to the same actual disk file.
320 * This generally depends on whether the platform uses suffixes to indicate
324 * If you do this, and open both file references for writing, the results are
325 * unpredictable. It is safest to change the type of a fileref only if it refers
326 * to a nonexistent file.
328 * If you change the mode of a fileref (#fileusage_TextMode,
329 * #fileusage_BinaryMode), but leave the rest of the type unchanged, the new
330 * fileref will definitely point to the same disk file as the old one.
332 * Obviously, if you write to a file in text mode and then read from it in
333 * binary mode, the results are platform-dependent.
335 * Returns: A new fileref, or %NULL if the fileref creation failed.
338 glk_fileref_create_from_fileref(glui32 usage, frefid_t fref, glui32 rock)
340 return fileref_new(fref->filename, rock, usage, fref->orig_filemode);
344 * glk_fileref_destroy:
345 * @fref: Fileref to destroy.
347 * Destroys a fileref which you have created. This does <emphasis>not</emphasis>
348 * affect the disk file; it just reclaims the resources allocated by the
349 * <code>glk_fileref_create...</code> function.
351 * It is legal to destroy a fileref after opening a file with it (while the
352 * file is still open.) The fileref is only used for the opening operation,
353 * not for accessing the file stream.
356 glk_fileref_destroy(frefid_t fref)
358 glk_data->fileref_list = g_list_delete_link(glk_data->fileref_list, fref->fileref_list);
360 g_free(fref->filename);
365 * glk_fileref_delete_file:
366 * @fref: A refrence to the file to delete.
368 * Deletes the file referred to by @fref. It does not destroy @fref itself.
371 glk_fileref_delete_file(frefid_t fref)
373 if( glk_fileref_does_file_exist(fref) )
374 if(g_unlink(fref->filename) == -1)
375 g_warning("Error deleting file %s", fref->filename);
379 * glk_fileref_does_file_exist:
380 * @fref: A fileref to check.
382 * Checks whether the file referred to by @fref exists.
384 * Returns: %TRUE (1) if @fref refers to an existing file, and %FALSE (0) if
388 glk_fileref_does_file_exist(frefid_t fref)
390 if( g_file_test(fref->filename, G_FILE_TEST_EXISTS) )