Een heleboel, relatief nutteloze dingen, zoals blank windows, en filerefs
[rodin/chimara.git] / src / stream.c
1 #include "stream.h"
2 #include <string.h>
3
4 /* Global current stream */
5 static strid_t current_stream = NULL;
6 /* List of streams currently in existence */
7 static GList *stream_list = NULL;
8
9 /**
10  * glk_stream_iterate:
11  * @str: A stream, or #NULL.
12  * @rockptr: Return location for the next window's rock, or #NULL.
13  *
14  * Iterates over the list of streams; if @str is #NULL, it returns the first
15  * stream, otherwise the next stream after @str. If there are no more, it
16  * returns #NULL. The stream's rock is stored in @rockptr. If you don't want
17  * the rocks to be returned, you may set @rockptr to #NULL.
18  *
19  * The order in which streams are returned is arbitrary. The order may change
20  * every time you create or destroy a stream, invalidating the iteration.
21  *
22  * Returns: the next stream, or #NULL if there are no more.
23  */
24 strid_t
25 glk_stream_iterate(strid_t str, glui32 *rockptr)
26 {
27         GList *retnode;
28         
29         if(str == NULL)
30                 retnode = stream_list;
31         else
32                 retnode = str->stream_list->next;
33         strid_t retval = retnode? (strid_t)retnode->data : NULL;
34                 
35         /* Store the stream's rock in rockptr */
36         if(retval && rockptr)
37                 *rockptr = glk_stream_get_rock(retval);
38                 
39         return retval;
40 }
41
42 /**
43  * glk_stream_get_rock:
44  * @str: A stream.
45  * 
46  * Returns the stream @str's rock value.
47  *
48  * Returns: A rock value.
49  */
50 glui32
51 glk_stream_get_rock(strid_t str)
52 {
53         g_return_val_if_fail(str != NULL, 0);
54         return str->rock;
55 }
56
57 /* Internal function: create a window stream to go with window. */
58 strid_t
59 window_stream_new(winid_t window)
60 {
61         /* Create stream and connect it to window */
62         strid_t s = g_new0(struct glk_stream_struct, 1);
63         s->file_mode = filemode_Write;
64         s->stream_type = STREAM_TYPE_WINDOW;
65         s->window = window;
66         /* Add it to the global stream list */
67         stream_list = g_list_prepend(stream_list, s);
68         s->stream_list = stream_list;
69
70         return s;
71 }
72
73 /**
74  * glk_stream_set_current:
75  * @str: An output stream, or NULL.
76  *
77  * Sets the current stream to @str, or to nothing if @str is #NULL.
78  */
79 void
80 glk_stream_set_current(strid_t str)
81 {
82         if(str != NULL && str->file_mode != filemode_Write)
83         {
84                 g_warning("glk_stream_set_current: "
85                         "Cannot set current stream to non output stream");
86                 return;
87         }
88
89         current_stream = str;
90 }
91
92 /* Internal function: change illegal (control) characters in a string to a
93 placeholder character. Must free returned string afterwards. */
94 static gchar *
95 remove_latin1_control_characters(gchar *s)
96 {
97         gchar *retval = g_strdup(s);
98         unsigned char *ptr;
99         for(ptr = (unsigned char *)retval; *ptr != '\0'; ptr++)
100                 if( (*ptr < 32 && *ptr != 10) || (*ptr >= 127 && *ptr <= 159) )
101                         *ptr = '?';
102                         /* Our placeholder character is '?'; other options are possible,
103                         like printing "0x7F" or something */
104         return retval;
105 }
106
107 /**
108  * glk_put_string:
109  * @s: A null-terminated string in Latin-1 encoding.
110  *
111  * Prints @s to the current stream.
112  */
113 void
114 glk_put_string(char *s)
115 {
116         /* Illegal to print to the current stream if it is NULL */
117         g_return_if_fail(current_stream != NULL);
118         
119         GError *error = NULL;
120         gchar *canonical, *utf8;
121
122         switch(current_stream->stream_type)
123         {
124                 case STREAM_TYPE_WINDOW:
125                         canonical = remove_latin1_control_characters(s);
126                         utf8 = g_convert(canonical, -1, "UTF-8", "ISO-8859-1", NULL, NULL, 
127                                          &error);
128                         g_free(canonical);
129                         
130                         if(utf8 == NULL)
131                         {
132                                 g_warning("glk_put_string: "
133                                         "Error during latin1->utf8 conversion: %s", 
134                                         error->message);
135                                 g_error_free(error);
136                                 return;
137                         }
138
139                         /* Each window type has a different way of printing to it */
140                         switch(current_stream->window->window_type)
141                         {
142                                 /* Printing to a these windows' streams does nothing */
143                                 case wintype_Blank:
144                                 case wintype_Pair:
145                                 case wintype_Graphics:
146                                         current_stream->write_count += strlen(s);
147                                         break;
148                                 /* Text buffer window */        
149                                 case wintype_TextBuffer:
150                                 {
151                                         GtkTextBuffer *buffer = gtk_text_view_get_buffer( 
152                                                 GTK_TEXT_VIEW(current_stream->window->widget) );
153
154                                         GtkTextIter iter;
155                                         gtk_text_buffer_get_end_iter(buffer, &iter);
156
157                                         gtk_text_buffer_insert(buffer, &iter, utf8, -1);
158                                 }
159                                         current_stream->write_count += strlen(s);
160                                         break;
161                                 default:
162                                         g_warning("glk_put_string: "
163                                                 "Writing to this kind of window unsupported.");
164                         }
165                         
166                         g_free(utf8);
167                         break;
168                 default:
169                         g_warning("glk_put_string: "
170                                 "Writing to this kind of stream unsupported."); 
171         }
172 }