4 #include <glib/gstdio.h>
6 #include "chimara-glk-private.h"
7 extern ChimaraGlkPrivate *glk_data;
9 /* Internal function: create a window stream to go with window. */
11 window_stream_new(winid_t window)
13 /* Create stream and connect it to window */
14 strid_t str = g_new0(struct glk_stream_struct, 1);
15 str->file_mode = filemode_Write;
16 str->type = STREAM_TYPE_WINDOW;
19 /* Add it to the global stream list */
20 glk_data->stream_list = g_list_prepend(glk_data->stream_list, str);
21 str->stream_list = glk_data->stream_list;
28 * @str: A stream, or %NULL.
29 * @rockptr: Return location for the next window's rock, or %NULL.
31 * Iterates over the list of streams; if @str is %NULL, it returns the first
32 * stream, otherwise the next stream after @str. If there are no more, it
33 * returns %NULL. The stream's rock is stored in @rockptr. If you don't want
34 * the rocks to be returned, you may set @rockptr to %NULL.
36 * The order in which streams are returned is arbitrary. The order may change
37 * every time you create or destroy a stream, invalidating the iteration.
39 * Returns: the next stream, or %NULL if there are no more.
42 glk_stream_iterate(strid_t str, glui32 *rockptr)
47 retnode = glk_data->stream_list;
49 retnode = str->stream_list->next;
50 strid_t retval = retnode? (strid_t)retnode->data : NULL;
52 /* Store the stream's rock in rockptr */
54 *rockptr = glk_stream_get_rock(retval);
60 * glk_stream_get_rock:
63 * Returns the stream @str's rock value.
65 * Returns: A rock value.
68 glk_stream_get_rock(strid_t str)
70 g_return_val_if_fail(str != NULL, 0);
75 * glk_stream_set_current:
76 * @str: An output stream, or %NULL.
78 * Sets the current stream to @str, which must be an output stream. You may set
79 * the current stream to %NULL, which means the current stream is not set to
83 glk_stream_set_current(strid_t str)
85 if(str != NULL && str->file_mode == filemode_Read)
87 g_warning("%s: Cannot set current stream to non output stream", __func__);
91 glk_data->current_stream = str;
95 * glk_stream_get_current:
97 * Returns the current stream, or %NULL if there is none.
102 glk_stream_get_current()
104 return glk_data->current_stream;
109 * @ch: A character in Latin-1 encoding.
111 * Prints one character to the current stream. As with all basic functions, the
112 * character is assumed to be in the Latin-1 character encoding.
115 glk_put_char(unsigned char ch)
117 g_return_if_fail(glk_data->current_stream != NULL);
118 glk_put_char_stream(glk_data->current_stream, ch);
123 * @s: A null-terminated string in Latin-1 encoding.
125 * Prints a null-terminated string to the current stream. It is exactly
127 * <informalexample><programlisting>
128 * for (ptr = s; *ptr; ptr++)
129 * glk_put_char(*ptr);
130 * </programlisting></informalexample>
131 * However, it may be more efficient.
134 glk_put_string(char *s)
136 g_return_if_fail(glk_data->current_stream != NULL);
137 glk_put_string_stream(glk_data->current_stream, s);
142 * @buf: An array of characters in Latin-1 encoding.
143 * @len: Length of @buf.
145 * Prints a block of characters to the current stream. It is exactly equivalent
147 * <informalexample><programlisting>
148 * for (i = 0; i < len; i++)
149 * glk_put_char(buf[i]);
150 * </programlisting></informalexample>
151 * However, it may be more efficient.
154 glk_put_buffer(char *buf, glui32 len)
156 g_return_if_fail(glk_data->current_stream != NULL);
157 glk_put_buffer_stream(glk_data->current_stream, buf, len);
161 * glk_stream_open_memory:
162 * @buf: An allocated buffer, or %NULL.
163 * @buflen: Length of @buf.
164 * @fmode: Mode in which the buffer will be opened. Must be one of
165 * #filemode_Read, #filemode_Write, or #filemode_ReadWrite.
166 * @rock: The new stream's rock value.
168 * Opens a stream which reads from or writes to a space in memory. @buf points
169 * to the buffer where output will be read from or written to. @buflen is the
170 * length of the buffer.
172 * When outputting, if more than @buflen characters are written to the stream,
173 * all of them beyond the buffer length will be thrown away, so as not to
174 * overwrite the buffer. (The character count of the stream will still be
175 * maintained correctly. That is, it will count the number of characters written
176 * into the stream, not the number that fit into the buffer.)
178 * If @buf is %NULL, or for that matter if @buflen is zero, then <emphasis>
179 * everything</emphasis> written to the stream is thrown away. This may be
180 * useful if you are interested in the character count.
182 * When inputting, if more than @buflen characters are read from the stream, the
183 * stream will start returning -1 (signalling end-of-file.) If @buf is %NULL,
184 * the stream will always return end-of-file.
186 * The data is written to the buffer exactly as it was passed to the printing
187 * functions (glk_put_char(), etc.); input functions will read the data exactly
188 * as it exists in memory. No platform-dependent cookery will be done on it.
189 * (You can write a disk file in text mode, but a memory stream is effectively
190 * always in binary mode.)
192 * Unicode values (characters greater than 255) cannot be written to the buffer.
193 * If you try, they will be stored as 0x3F ("?") characters.
195 * Whether reading or writing, the contents of the buffer are undefined until
196 * the stream is closed. The library may store the data there as it is written,
197 * or deposit it all in a lump when the stream is closed. It is illegal to
198 * change the contents of the buffer while the stream is open.
201 glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock)
203 g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
205 strid_t str = g_new0(struct glk_stream_struct, 1);
207 str->file_mode = fmode;
208 str->type = STREAM_TYPE_MEMORY;
211 str->buflen = buflen;
212 str->unicode = FALSE;
214 /* Add it to the global stream list */
215 glk_data->stream_list = g_list_prepend(glk_data->stream_list, str);
216 str->stream_list = glk_data->stream_list;
222 * glk_stream_open_memory_uni:
223 * @buf: An allocated buffer, or %NULL.
224 * @buflen: Length of @buf.
225 * @fmode: Mode in which the buffer will be opened. Must be one of
226 * #filemode_Read, #filemode_Write, or #filemode_ReadWrite.
227 * @rock: The new stream's rock value.
229 * Works just like glk_stream_open_memory(), except that the buffer is an array
230 * of 32-bit words, instead of bytes. This allows you to write and read any
231 * Unicode character. The @buflen is the number of words, not the number of
235 glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode, glui32 rock)
237 g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
239 strid_t str = g_new0(struct glk_stream_struct, 1);
241 str->file_mode = fmode;
242 str->type = STREAM_TYPE_MEMORY;
245 str->buflen = buflen;
248 /* Add it to the global stream list */
249 glk_data->stream_list = g_list_prepend(glk_data->stream_list, str);
250 str->stream_list = glk_data->stream_list;
255 /* Internal function: create a stream using the given parameters. */
257 file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode)
259 g_return_val_if_fail(fileref != NULL, NULL);
262 /* Binary mode is 0x000, text mode 0x100 */
263 gboolean binary = !(fileref->usage & fileusage_TextMode);
267 if(!g_file_test(fileref->filename, G_FILE_TEST_EXISTS)) {
268 g_warning("glk_stream_open_file: Tried to open a file in read "
269 "mode that didn't exist!");
272 modestr = g_strdup(binary? "rb" : "r");
275 modestr = g_strdup(binary? "wb" : "w");
277 case filemode_WriteAppend:
278 modestr = g_strdup(binary? "ab" : "a");
280 case filemode_ReadWrite:
281 if( g_file_test(fileref->filename, G_FILE_TEST_EXISTS) ) {
282 modestr = g_strdup(binary? "r+b" : "r+");
284 modestr = g_strdup(binary? "w+b" : "w+");
288 g_warning("glk_stream_open_file: Invalid file mode");
292 FILE *fp = g_fopen(fileref->filename, modestr);
295 g_warning("glk_stream_open_file: Error opening file");
299 /* If they opened a file in write mode but didn't specifically get
300 permission to do so, complain if the file already exists */
301 if(fileref->orig_filemode == filemode_Read && fmode != filemode_Read) {
304 GtkWidget *dialog = gtk_message_dialog_new(NULL, 0,
305 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
306 "File %s already exists. Overwrite?", fileref->filename);
307 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
308 gtk_widget_destroy(dialog);
312 if(response != GTK_RESPONSE_YES) {
318 strid_t str = g_new0(struct glk_stream_struct, 1);
320 str->file_mode = fmode;
321 str->type = STREAM_TYPE_FILE;
322 str->file_pointer = fp;
323 str->binary = binary;
324 str->unicode = unicode;
325 str->filename = g_filename_to_utf8(fileref->filename, -1, NULL, NULL, NULL);
326 if(str->filename == NULL)
327 str->filename = g_strdup("Unknown file name"); /* fail silently */
328 /* Add it to the global stream list */
329 glk_data->stream_list = g_list_prepend(glk_data->stream_list, str);
330 str->stream_list = glk_data->stream_list;
336 * glk_stream_open_file:
337 * @fileref: Indicates the file which will be opened.
338 * @fmode: Mode in which the file will be opened. Can be any of #filemode_Read,
339 * #filemode_Write, #filemode_WriteAppend, or #filemode_ReadWrite.
340 * @rock: The new stream's rock value.
342 * Opens a stream which reads to or writes from a disk file. If @fmode is
343 * #filemode_Read, the file must already exist; for the other modes, an empty
344 * file is created if none exists. If @fmode is #filemode_Write, and the file
345 * already exists, it is truncated down to zero length (an empty file). If
346 * @fmode is #filemode_WriteAppend, the file mark is set to the end of the
349 * The file may be written in text or binary mode; this is determined by the
350 * @fileref argument. Similarly, platform-dependent attributes such as file
351 * type are determined by @fileref.
353 * When writing in binary mode, Unicode values (characters greater than 255)
354 * cannot be written to the file. If you try, they will be stored as 0x3F ("?")
355 * characters. In text mode, Unicode values are stored in UTF-8.
357 * Returns: A new stream, or %NULL if the file operation failed.
360 glk_stream_open_file(frefid_t fileref, glui32 fmode, glui32 rock)
362 return file_stream_new(fileref, fmode, rock, FALSE);
366 * glk_stream_open_file_uni:
367 * @fileref: Indicates the file which will be opened.
368 * @fmode: Mode in which the file will be opened. Can be any of #filemode_Read,
369 * #filemode_Write, #filemode_WriteAppend, or #filemode_ReadWrite.
370 * @rock: The new stream's rock value.
372 * This works just like glk_stream_open_file(), except that in binary mode,
373 * characters are written and read as four-byte (big-endian) values. This
374 * allows you to write any Unicode character.
376 * In text mode, the file is written and read in UTF-8.
378 * Returns: A new stream, or %NULL if the file operation failed.
381 glk_stream_open_file_uni(frefid_t fileref, glui32 fmode, glui32 rock)
383 return file_stream_new(fileref, fmode, rock, TRUE);
388 * @str: Stream to close.
389 * @result: Pointer to a #stream_result_t, or %NULL.
391 * Closes the stream @str. The @result argument points to a structure which is
392 * filled in with the final character counts of the stream. If you do not care
393 * about these, you may pass %NULL as the @result argument.
395 * If @str is the current output stream, the current output stream is set to
398 * You cannot close window streams; use glk_window_close() instead.
401 glk_stream_close(strid_t str, stream_result_t *result)
403 g_return_if_fail(str != NULL);
405 /* Free resources associated with one specific type of stream */
408 case STREAM_TYPE_WINDOW:
409 g_warning("%s: Attempted to close a window stream. Use glk_window_"
410 "close() instead.", __func__);
413 case STREAM_TYPE_MEMORY:
417 case STREAM_TYPE_FILE:
418 if(fclose(str->file_pointer) != 0)
419 g_warning("%s: Failed to close file '%s'.", __func__,
421 g_free(str->filename);
424 g_warning("%s: Closing this type of stream not supported.",
429 stream_close_common(str, result);
432 /* Internal function: Stuff to do upon closing any type of stream. */
434 stream_close_common(strid_t str, stream_result_t *result)
436 /* Remove the stream from the global stream list */
437 glk_data->stream_list = g_list_delete_link(glk_data->stream_list, str->stream_list);
439 /* If it was the current output stream, set that to NULL */
440 if(glk_data->current_stream == str)
441 glk_data->current_stream = NULL;
443 /* If it was one or more windows' echo streams, set those to NULL */
445 for(win = glk_window_iterate(NULL, NULL); win;
446 win = glk_window_iterate(win, NULL))
447 if(win->echo_stream == str)
448 win->echo_stream = NULL;
450 /* Return the character counts */
453 result->readcount = str->read_count;
454 result->writecount = str->write_count;