4 #include <glib/gstdio.h>
6 /* Global current stream */
7 static strid_t current_stream = NULL;
8 /* List of streams currently in existence */
9 static GList *stream_list = NULL;
11 /* Internal function: create a window stream to go with window. */
13 window_stream_new(winid_t window)
15 /* Create stream and connect it to window */
16 strid_t s = g_new0(struct glk_stream_struct, 1);
17 s->file_mode = filemode_Write;
18 s->stream_type = STREAM_TYPE_WINDOW;
20 /* Add it to the global stream list */
21 stream_list = g_list_prepend(stream_list, s);
22 s->stream_list = stream_list;
29 * @str: A stream, or #NULL.
30 * @rockptr: Return location for the next window's rock, or #NULL.
32 * Iterates over the list of streams; if @str is #NULL, it returns the first
33 * stream, otherwise the next stream after @str. If there are no more, it
34 * returns #NULL. The stream's rock is stored in @rockptr. If you don't want
35 * the rocks to be returned, you may set @rockptr to #NULL.
37 * The order in which streams are returned is arbitrary. The order may change
38 * every time you create or destroy a stream, invalidating the iteration.
40 * Returns: the next stream, or #NULL if there are no more.
43 glk_stream_iterate(strid_t str, glui32 *rockptr)
48 retnode = stream_list;
50 retnode = str->stream_list->next;
51 strid_t retval = retnode? (strid_t)retnode->data : NULL;
53 /* Store the stream's rock in rockptr */
55 *rockptr = glk_stream_get_rock(retval);
61 * glk_stream_get_rock:
64 * Returns the stream @str's rock value.
66 * Returns: A rock value.
69 glk_stream_get_rock(strid_t str)
71 g_return_val_if_fail(str != NULL, 0);
76 * glk_stream_set_current:
77 * @str: An output stream, or NULL.
79 * Sets the current stream to @str, or to nothing if @str is #NULL.
82 glk_stream_set_current(strid_t str)
84 if(str != NULL && str->file_mode == filemode_Read)
86 g_warning("glk_stream_set_current: "
87 "Cannot set current stream to non output stream");
95 * glk_stream_get_current:
97 * Returns the current stream, or #NULL if there is none.
102 glk_stream_get_current()
104 return current_stream;
109 * @ch: A character in Latin-1 encoding.
111 * Prints one character @ch to the current stream.
114 glk_put_char(unsigned char ch)
116 /* Illegal to print to the current stream if it is NULL */
117 g_return_if_fail(current_stream != NULL);
118 glk_put_char_stream(current_stream, ch);
123 * @s: A null-terminated string in Latin-1 encoding.
125 * Prints @s to the current stream.
128 glk_put_string(char *s)
130 /* Illegal to print to the current stream if it is NULL */
131 g_return_if_fail(current_stream != NULL);
132 glk_put_string_stream(current_stream, s);
137 * @buf: An array of characters in Latin-1 encoding.
138 * @len: Length of @buf.
140 * Prints @buf to the current stream.
143 glk_put_buffer(char *buf, glui32 len)
145 /* Illegal to print to the current stream if it is NULL */
146 g_return_if_fail(current_stream != NULL);
147 glk_put_buffer_stream(current_stream, buf, len);
151 * glk_stream_open_memory:
152 * @buf: An allocated buffer, or %NULL.
153 * @buflen: Length of @buf.
154 * @fmode: Mode in which the buffer will be opened. Must be one of
155 * #filemode_Read, #filemode_Write, or #filemode_ReadWrite.
156 * @rock: The new stream's rock value.
158 * Opens a stream which reads from or writes to a space in memory. @buf points
159 * to the buffer where output will be read from or written to. @buflen is the
160 * length of the buffer.
162 * When outputting, if more than @buflen characters are written to the stream,
163 * all of them beyond the buffer length will be thrown away, so as not to
164 * overwrite the buffer. (The character count of the stream will still be
165 * maintained correctly. That is, it will count the number of characters written
166 * into the stream, not the number that fit into the buffer.)
168 * If @buf is %NULL, or for that matter if @buflen is zero, then <emphasis>
169 * everything</emphasis> written to the stream is thrown away. This may be
170 * useful if you are interested in the character count.
172 * When inputting, if more than @buflen characters are read from the stream, the
173 * stream will start returning -1 (signalling end-of-file.) If @buf is %NULL,
174 * the stream will always return end-of-file.
176 * The data is written to the buffer exactly as it was passed to the printing
177 * functions (glk_put_char(), etc.); input functions will read the data exactly
178 * as it exists in memory. No platform-dependent cookery will be done on it.
179 * [You can write a disk file in text mode, but a memory stream is effectively
180 * always in binary mode.]
182 * Unicode values (characters greater than 255) cannot be written to the buffer.
183 * If you try, they will be stored as 0x3F ("?") characters.
185 * Whether reading or writing, the contents of the buffer are undefined until
186 * the stream is closed. The library may store the data there as it is written,
187 * or deposit it all in a lump when the stream is closed. It is illegal to
188 * change the contents of the buffer while the stream is open.
191 glk_stream_open_memory(char *buf, glui32 buflen, glui32 fmode, glui32 rock)
193 g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
195 strid_t s = g_new0(struct glk_stream_struct, 1);
197 s->file_mode = fmode;
198 s->stream_type = STREAM_TYPE_MEMORY;
204 /* Add it to the global stream list */
205 stream_list = g_list_prepend(stream_list, s);
206 s->stream_list = stream_list;
212 * glk_stream_open_memory_uni:
213 * @buf: An allocated buffer, or %NULL.
214 * @buflen: Length of @buf.
215 * @fmode: Mode in which the buffer will be opened. Must be one of
216 * #filemode_Read, #filemode_Write, or #filemode_ReadWrite.
217 * @rock: The new stream's rock value.
219 * Works just like glk_stream_open_memory(), except that the buffer is an array
220 * of 32-bit words, instead of bytes. This allows you to write and read any
221 * Unicode character. The @buflen is the number of words, not the number of
225 glk_stream_open_memory_uni(glui32 *buf, glui32 buflen, glui32 fmode,
228 g_return_val_if_fail(fmode != filemode_WriteAppend, NULL);
230 strid_t s = g_new0(struct glk_stream_struct, 1);
232 s->file_mode = fmode;
233 s->stream_type = STREAM_TYPE_MEMORY;
239 /* Add it to the global stream list */
240 stream_list = g_list_prepend(stream_list, s);
241 s->stream_list = stream_list;
246 /* Internal function: create a stream using the given parameters. */
248 file_stream_new(frefid_t fileref, glui32 fmode, glui32 rock, gboolean unicode)
250 g_return_val_if_fail(fileref != NULL, NULL);
253 /* Binary mode is 0x000, text mode 0x100 */
254 gboolean binary = !(fileref->usage & fileusage_TextMode);
258 if(!g_file_test(fileref->filename, G_FILE_TEST_EXISTS)) {
259 g_warning("glk_stream_open_file: Tried to open a file in read "
260 "mode that didn't exist!");
263 modestr = g_strdup(binary? "rb" : "r");
266 modestr = g_strdup(binary? "wb" : "w");
268 case filemode_WriteAppend:
269 modestr = g_strdup(binary? "ab" : "a");
271 case filemode_ReadWrite:
272 modestr = g_strdup(binary? "r+b" : "r+");
275 g_warning("glk_stream_open_file: Invalid file mode");
279 FILE *fp = g_fopen(fileref->filename, modestr);
282 g_warning("glk_stream_open_file: Error opening file");
286 /* If they opened a file in write mode but didn't specifically get
287 permission to do so, complain if the file already exists */
288 if(fileref->orig_filemode == filemode_Read && fmode != filemode_Read) {
289 GtkWidget *dialog = gtk_message_dialog_new(NULL, 0,
290 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
291 "File %s already exists. Overwrite?", fileref->filename);
292 gint response = gtk_dialog_run(GTK_DIALOG(dialog));
293 gtk_widget_destroy(dialog);
294 if(response != GTK_RESPONSE_YES) {
300 strid_t s = g_new0(struct glk_stream_struct, 1);
302 s->file_mode = fmode;
303 s->stream_type = STREAM_TYPE_FILE;
304 s->file_pointer = fp;
306 s->unicode = unicode;
307 s->filename = g_filename_to_utf8(fileref->filename, -1, NULL, NULL, NULL);
308 if(s->filename == NULL)
309 s->filename = g_strdup("Unknown file name"); /* fail silently */
310 /* Add it to the global stream list */
311 stream_list = g_list_prepend(stream_list, s);
312 s->stream_list = stream_list;
318 * glk_stream_open_file:
319 * @fileref: Indicates the file which will be opened.
320 * @fmode: Mode in which the file will be opened. Can be any of #filemode_Read,
321 * #filemode_Write, #filemode_WriteAppend, or #filemode_ReadWrite.
322 * @rock: The new stream's rock value.
324 * Opens a stream which reads to or writes from a disk file. If @fmode is
325 * #filemode_Read, the file must already exist; for the other modes, an empty
326 * file is created if none exists. If @fmode is #filemode_Write, and the file
327 * already exists, it is truncated down to zero length (an empty file). If
328 * @fmode is #filemode_WriteAppend, the file mark is set to the end of the
331 * The file may be written in text or binary mode; this is determined by the
332 * @fileref argument. Similarly, platform-dependent attributes such as file
333 * type are determined by @fileref.
335 * When writing in binary mode, Unicode values (characters greater than 255)
336 * cannot be written to the file. If you try, they will be stored as 0x3F ("?")
337 * characters. In text mode, Unicode values are stored in UTF-8.
339 * Returns: A new stream, or %NULL if the file operation failed.
342 glk_stream_open_file(frefid_t fileref, glui32 fmode, glui32 rock)
344 return file_stream_new(fileref, fmode, rock, FALSE);
348 * glk_stream_open_file_uni:
349 * @fileref: Indicates the file which will be opened.
350 * @fmode: Mode in which the file will be opened. Can be any of #filemode_Read,
351 * #filemode_Write, #filemode_WriteAppend, or #filemode_ReadWrite.
352 * @rock: The new stream's rock value.
354 * This works just like glk_stream_open_file(), except that in binary mode,
355 * characters are written and read as four-byte (big-endian) values. This
356 * allows you to write any Unicode character.
358 * In text mode, the file is written and read in UTF-8.
360 * Returns: A new stream, or %NULL if the file operation failed.
363 glk_stream_open_file_uni(frefid_t fileref, glui32 fmode, glui32 rock)
365 return file_stream_new(fileref, fmode, rock, TRUE);
370 * @str: Stream to close.
371 * @result: Pointer to a #stream_result_t, or %NULL.
373 * Closes the stream @str. The @result argument points to a structure which is
374 * filled in with the final character counts of the stream. If you do not care
375 * about these, you may pass %NULL as the @result argument.
377 * If @str is the current output stream, the current output stream is set to
380 * You cannot close window streams; use glk_window_close() instead.
383 glk_stream_close(strid_t str, stream_result_t *result)
385 g_return_if_fail(str != NULL);
387 /* Free resources associated with one specific type of stream */
388 switch(str->stream_type)
390 case STREAM_TYPE_WINDOW:
391 g_warning("%s: Attempted to close a window stream. Use glk_window_"
392 "close() instead.", __func__);
395 case STREAM_TYPE_MEMORY:
399 case STREAM_TYPE_FILE:
400 if(fclose(str->file_pointer) != 0)
401 g_warning("%s: Failed to close file '%s'.", __func__,
403 g_free(str->filename);
406 g_warning("%s: Closing this type of stream not supported.",
411 /* Remove the stream from the global stream list */
412 stream_list = g_list_delete_link(stream_list, str->stream_list);
413 /* If it was the current output stream, set that to NULL */
414 if(current_stream == str)
415 current_stream = NULL;
416 /* If it was one or more windows' echo streams, set those to NULL */
418 for(win = glk_window_iterate(NULL, NULL); win;
419 win = glk_window_iterate(win, NULL))
420 if(win->echo_stream == str)
421 win->echo_stream = NULL;
422 /* Return the character counts */
425 result->readcount = str->read_count;
426 result->writecount = str->write_count;