6 #include <glib/gstdio.h>
10 **************** WRITING FUNCTIONS ********************************************
14 /* Internal function: write a UTF-8 string to a text grid window's text buffer. */
16 write_utf8_to_grid(winid_t win, gchar *s)
18 /* Number of characters to insert */
19 glong length = g_utf8_strlen(s, -1);
20 glong chars_left = length;
24 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
25 GtkTextMark *cursor = gtk_text_buffer_get_mark(buffer, "cursor_position");
27 /* Get cursor position */
29 gtk_text_buffer_get_iter_at_mark(buffer, &start, cursor);
30 /* Spaces available on this line */
31 gint available_space = win->width - gtk_text_iter_get_line_offset(&start);
33 while(chars_left > available_space && !gtk_text_iter_is_end(&start))
35 GtkTextIter end = start;
36 gtk_text_iter_forward_to_line_end(&end);
37 gtk_text_buffer_delete(buffer, &start, &end);
38 gtk_text_buffer_insert(buffer, &start, s + (length - chars_left), available_space);
39 chars_left -= available_space;
40 gtk_text_iter_forward_line(&start);
41 available_space = win->width;
43 if(!gtk_text_iter_is_end(&start))
45 GtkTextIter end = start;
46 gtk_text_iter_forward_chars(&end, chars_left);
47 gtk_text_buffer_delete(buffer, &start, &end);
48 gtk_text_buffer_insert(buffer, &start, s + (length - chars_left), -1);
51 gtk_text_buffer_move_mark(buffer, cursor, &start);
56 /* Internal function: write a UTF-8 string to a text buffer window's text buffer. */
58 write_utf8_to_window(winid_t win, gchar *s)
62 GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(win->widget) );
65 gtk_text_buffer_get_end_iter(buffer, &iter);
66 gtk_text_buffer_insert(buffer, &iter, s, -1);
71 /* Internal function: write a Latin-1 buffer with length to a stream. */
73 write_buffer_to_stream(strid_t str, gchar *buf, glui32 len)
77 case STREAM_TYPE_WINDOW:
78 /* Each window type has a different way of printing to it */
79 switch(str->window->type)
81 /* Printing to these windows' streams does nothing */
84 case wintype_Graphics:
85 str->write_count += len;
88 /* Text grid window */
89 case wintype_TextGrid:
91 gchar *utf8 = convert_latin1_to_utf8(buf, len);
94 /* FIXME: What to do if string contains \n? Split the input string at newlines and write each string separately? */
95 write_utf8_to_grid(str->window, utf8);
99 str->write_count += len;
102 /* Text buffer window */
103 case wintype_TextBuffer:
105 gchar *utf8 = convert_latin1_to_utf8(buf, len);
108 write_utf8_to_window(str->window, utf8);
112 str->write_count += len;
115 g_warning("%s: Writing to this kind of window unsupported.", __func__);
118 /* Now write the same buffer to the window's echo stream */
119 if(str->window->echo_stream != NULL)
120 write_buffer_to_stream(str->window->echo_stream, buf, len);
124 case STREAM_TYPE_MEMORY:
125 if(str->unicode && str->ubuffer)
128 while(str->mark < str->buflen && foo < len)
129 str->ubuffer[str->mark++] = (unsigned char)buf[foo++];
131 if(!str->unicode && str->buffer)
133 int copycount = MIN(len, str->buflen - str->mark);
134 memmove(str->buffer + str->mark, buf, copycount);
135 str->mark += copycount;
138 str->write_count += len;
141 case STREAM_TYPE_FILE:
146 gchar *writebuffer = convert_latin1_to_ucs4be_string(buf, len);
147 fwrite(writebuffer, sizeof(gchar), len * 4, str->file_pointer);
150 else /* Regular file */
152 fwrite(buf, sizeof(gchar), len, str->file_pointer);
155 else /* Text mode is the same for Unicode and regular files */
157 gchar *utf8 = convert_latin1_to_utf8(buf, len);
160 g_fprintf(str->file_pointer, "%s", utf8);
165 str->write_count += len;
168 g_warning("%s: Writing to this kind of stream unsupported.", __func__);
172 /* Internal function: write a Unicode buffer with length to a stream. */
174 write_buffer_to_stream_uni(strid_t str, glui32 *buf, glui32 len)
178 case STREAM_TYPE_WINDOW:
179 /* Each window type has a different way of printing to it */
180 switch(str->window->type)
182 /* Printing to these windows' streams does nothing */
185 case wintype_Graphics:
186 str->write_count += len;
189 /* Text grid window */
190 case wintype_TextGrid:
192 gchar *utf8 = convert_ucs4_to_utf8(buf, len);
195 /* FIXME: What to do if string contains \n? Split the input string at newlines and write each string separately? */
196 write_utf8_to_grid(str->window, utf8);
200 str->write_count += len;
203 /* Text buffer window */
204 case wintype_TextBuffer:
206 gchar *utf8 = convert_ucs4_to_utf8(buf, len);
209 write_utf8_to_window(str->window, utf8);
213 str->write_count += len;
216 g_warning("%s: Writing to this kind of window unsupported.", __func__);
219 /* Now write the same buffer to the window's echo stream */
220 if(str->window->echo_stream != NULL)
221 write_buffer_to_stream_uni(str->window->echo_stream, buf, len);
225 case STREAM_TYPE_MEMORY:
226 if(str->unicode && str->ubuffer)
228 int copycount = MIN(len, str->buflen - str->mark);
229 memmove(str->ubuffer + str->mark, buf, copycount * sizeof(glui32));
230 str->mark += copycount;
232 if(!str->unicode && str->buffer)
234 gchar *latin1 = convert_ucs4_to_latin1_binary(buf, len);
235 int copycount = MIN(len, str->buflen - str->mark);
236 memmove(str->buffer + str->mark, latin1, copycount);
238 str->mark += copycount;
241 str->write_count += len;
244 case STREAM_TYPE_FILE:
249 gchar *writebuffer = convert_ucs4_to_ucs4be_string(buf, len);
250 fwrite(writebuffer, sizeof(gchar), len * 4, str->file_pointer);
253 else /* Regular file */
255 gchar *latin1 = convert_ucs4_to_latin1_binary(buf, len);
256 fwrite(latin1, sizeof(gchar), len, str->file_pointer);
260 else /* Text mode is the same for Unicode and regular files */
262 gchar *utf8 = convert_ucs4_to_utf8(buf, len);
265 g_fprintf(str->file_pointer, "%s", utf8);
270 str->write_count += len;
273 g_warning("%s: Writing to this kind of stream unsupported.", __func__);
278 * glk_put_char_stream:
279 * @str: An output stream.
280 * @ch: A character in Latin-1 encoding.
282 * The same as glk_put_char(), except that you specify a stream @str to print
283 * to, instead of using the current stream. It is illegal for @str to be %NULL,
284 * or an input-only stream.
287 glk_put_char_stream(strid_t str, unsigned char ch)
289 g_return_if_fail(str != NULL);
290 g_return_if_fail(str->file_mode != filemode_Read);
292 write_buffer_to_stream(str, (gchar *)&ch, 1);
296 * glk_put_char_stream_uni:
297 * @str: An output stream.
298 * @ch: A Unicode code point.
300 * The same as glk_put_char_uni(), except that you specify a stream @str to
301 * print to, instead of using the current stream. It is illegal for @str to be
302 * %NULL, or an input-only stream.
305 glk_put_char_stream_uni(strid_t str, glui32 ch)
307 g_return_if_fail(str != NULL);
308 g_return_if_fail(str->file_mode != filemode_Read);
310 write_buffer_to_stream_uni(str, &ch, 1);
314 * glk_put_string_stream:
315 * @str: An output stream.
316 * @s: A null-terminated string in Latin-1 encoding.
318 * The same as glk_put_string(), except that you specify a stream @str to print
319 * to, instead of using the current stream. It is illegal for @str to be %NULL,
320 * or an input-only stream.
323 glk_put_string_stream(strid_t str, char *s)
325 g_return_if_fail(str != NULL);
326 g_return_if_fail(str->file_mode != filemode_Read);
328 write_buffer_to_stream(str, s, strlen(s));
332 * glk_put_string_stream_uni:
333 * @str: An output stream.
334 * @s: A null-terminated array of Unicode code points.
336 * The same as glk_put_string_uni(), except that you specify a stream @str to
337 * print to, instead of using the current stream. It is illegal for @str to be
338 * %NULL, or an input-only stream.
341 glk_put_string_stream_uni(strid_t str, glui32 *s)
343 g_return_if_fail(str != NULL);
344 g_return_if_fail(str->file_mode != filemode_Read);
346 /* An impromptu strlen() for glui32 arrays */
351 write_buffer_to_stream_uni(str, s, len);
355 * glk_put_buffer_stream:
356 * @str: An output stream.
357 * @buf: An array of characters in Latin-1 encoding.
358 * @len: Length of @buf.
360 * The same as glk_put_buffer(), except that you specify a stream @str to print
361 * to, instead of using the current stream. It is illegal for @str to be %NULL,
362 * or an input-only stream.
365 glk_put_buffer_stream(strid_t str, char *buf, glui32 len)
367 g_return_if_fail(str != NULL);
368 g_return_if_fail(str->file_mode != filemode_Read);
370 write_buffer_to_stream(str, buf, len);
374 * glk_put_buffer_stream_uni:
375 * @str: An output stream.
376 * @buf: An array of Unicode code points.
377 * @len: Length of @buf.
379 * The same as glk_put_buffer_uni(), except that you specify a stream @str to
380 * print to, instead of using the current stream. It is illegal for @str to be
381 * %NULL, or an input-only stream.
384 glk_put_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len)
386 g_return_if_fail(str != NULL);
387 g_return_if_fail(str->file_mode != filemode_Read);
389 write_buffer_to_stream_uni(str, buf, len);
394 **************** READING FUNCTIONS ********************************************
398 /* Internal function: Read one big-endian four-byte character from file fp and
399 return it as a Unicode code point, or -1 on EOF */
401 read_ucs4be_char_from_file(FILE *fp)
403 unsigned char readbuffer[4];
404 if(fread(readbuffer, sizeof(unsigned char), 4, fp) < 4)
407 readbuffer[0] << 24 |
408 readbuffer[1] << 16 |
413 /* Internal function: Read one UTF-8 character, which may be more than one byte,
414 from file fp and return it as a Unicode code point, or -1 on EOF */
416 read_utf8_char_from_file(FILE *fp)
418 gchar readbuffer[4] = {0, 0, 0, 0}; /* Max UTF-8 width */
420 gunichar charresult = (gunichar)-2;
421 for(foo = 0; foo < 4 && charresult == (gunichar)-2; foo++)
426 readbuffer[foo] = (gchar)ch;
427 charresult = g_utf8_get_char_validated(readbuffer, foo + 1);
428 /* charresult is -1 if invalid, -2 if incomplete, and the unicode code
431 /* Silently return unknown characters as 0xFFFD, Replacement Character */
432 if(charresult == (gunichar)-1 || charresult == (gunichar)-2)
437 /* Internal function: Tell whether this code point is a Unicode newline. The
438 file pointer and eight-bit flag are included in case the newline is a CR
439 (U+000D). If the next character is LF (U+000A) then it also belongs to the
442 is_unicode_newline(glsi32 ch, FILE *fp, gboolean utf8)
444 if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
447 glsi32 ch2 = utf8? read_utf8_char_from_file(fp) :
448 read_ucs4be_char_from_file(fp);
450 fseek(fp, utf8? -1 : -4, SEEK_CUR);
456 /* Internal function: Read one character from a stream. Returns a value which
457 can be returned unchanged by glk_get_char_stream_uni(), but
458 glk_get_char_stream() must replace high values by the placeholder character. */
460 get_char_stream_common(strid_t str)
464 case STREAM_TYPE_MEMORY:
467 if(!str->ubuffer || str->mark >= str->buflen)
469 glui32 ch = str->ubuffer[str->mark++];
475 if(!str->buffer || str->mark >= str->buflen)
477 unsigned char ch = str->buffer[str->mark++];
483 case STREAM_TYPE_FILE:
488 glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
494 else /* Regular file */
496 int ch = fgetc(str->file_pointer);
504 else /* Text mode is the same for Unicode and regular files */
506 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
514 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
520 * glk_get_char_stream:
521 * @str: An input stream.
523 * Reads one character from the stream @str. (There is no notion of a
524 * <quote>current input stream.</quote>) It is illegal for @str to be %NULL, or
525 * an output-only stream.
527 * The result will be between 0 and 255. As with all basic text functions, Glk
528 * assumes the Latin-1 encoding. See <link
529 * linkend="chimara-Character-Encoding">Character Encoding</link>. If the end
530 * of the stream has been reached, the result will be -1.
533 * Note that high-bit characters (128..255) are <emphasis>not</emphasis>
534 * returned as negative numbers.
537 * If the stream contains Unicode data — for example, if it was created
538 * with glk_stream_open_file_uni() or glk_stream_open_memory_uni() — then
539 * characters beyond 255 will be returned as 0x3F (<code>"?"</code>).
541 * It is usually more efficient to read several characters at once with
542 * glk_get_buffer_stream() or glk_get_line_stream(), as opposed to calling
543 * glk_get_char_stream() several times.
545 * Returns: A character value between 0 and 255, or -1 on end of stream.
548 glk_get_char_stream(strid_t str)
550 g_return_val_if_fail(str != NULL, -1);
551 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, -1);
553 glsi32 ch = get_char_stream_common(str);
554 return (ch > 0xFF)? PLACEHOLDER : ch;
558 * glk_get_char_stream_uni:
559 * @str: An input stream.
561 * Reads one character from the stream @str. The result will be between 0 and
562 * 0x7FFFFFFF. If the end of the stream has been reached, the result will be -1.
564 * Returns: A value between 0 and 0x7FFFFFFF, or -1 on end of stream.
567 glk_get_char_stream_uni(strid_t str)
569 g_return_val_if_fail(str != NULL, -1);
570 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, -1);
572 return get_char_stream_common(str);
576 * glk_get_buffer_stream:
577 * @str: An input stream.
578 * @buf: A buffer with space for at least @len characters.
579 * @len: The number of characters to read.
581 * Reads @len characters from @str, unless the end of stream is reached first.
582 * No terminal null is placed in the buffer.
584 * Returns: The number of characters actually read.
587 glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
589 g_return_val_if_fail(str != NULL, 0);
590 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
591 g_return_val_if_fail(buf != NULL, 0);
595 case STREAM_TYPE_MEMORY:
600 while(copycount < len && str->ubuffer && str->mark < str->buflen)
602 glui32 ch = str->ubuffer[str->mark++];
603 buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
608 if(str->buffer) /* if not, copycount stays 0 */
609 copycount = MIN(len, str->buflen - str->mark);
610 memmove(buf, str->buffer + str->mark, copycount);
611 str->mark += copycount;
614 str->read_count += copycount;
617 case STREAM_TYPE_FILE:
620 if(str->unicode) /* Binary file with 4-byte characters */
622 /* Read len characters of 4 bytes each */
623 unsigned char *readbuffer = g_new0(unsigned char, 4 * len);
624 size_t count = fread(readbuffer, sizeof(unsigned char), 4 * len, str->file_pointer);
625 /* If there was an incomplete character */
629 g_warning("%s: Incomplete character in binary Unicode file.", __func__);
633 for(foo = 0; foo < count; foo += 4)
635 glsi32 ch = readbuffer[foo] << 24
636 | readbuffer[foo + 1] << 16
637 | readbuffer[foo + 2] << 8
638 | readbuffer[foo + 3];
639 buf[foo / 4] = (ch > 255)? 0x3F : (char)ch;
642 str->read_count += count / 4;
645 else /* Regular binary file */
647 size_t count = fread(buf, sizeof(char), len, str->file_pointer);
648 str->read_count += count;
652 else /* Text mode is the same for Unicode and regular files */
654 /* Do it character-by-character */
656 for(foo = 0; foo < len; foo++)
658 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
662 buf[foo] = (ch > 0xFF)? 0x3F : (gchar)ch;
667 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
673 * glk_get_buffer_stream_uni:
674 * @str: An input stream.
675 * @buf: A buffer with space for at least @len Unicode code points.
676 * @len: The number of characters to read.
678 * Reads @len Unicode characters from @str, unless the end of stream is reached
679 * first. No terminal null is placed in the buffer.
681 * Returns: The number of Unicode characters actually read.
684 glk_get_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len)
686 g_return_val_if_fail(str != NULL, 0);
687 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
688 g_return_val_if_fail(buf != NULL, 0);
692 case STREAM_TYPE_MEMORY:
697 if(str->ubuffer) /* if not, copycount stays 0 */
698 copycount = MIN(len, str->buflen - str->mark);
699 memmove(buf, str->ubuffer + str->mark, copycount * 4);
700 str->mark += copycount;
704 while(copycount < len && str->buffer && str->mark < str->buflen)
706 unsigned char ch = str->buffer[str->mark++];
707 buf[copycount++] = ch;
711 str->read_count += copycount;
714 case STREAM_TYPE_FILE:
717 if(str->unicode) /* Binary file with 4-byte characters */
719 /* Read len characters of 4 bytes each */
720 unsigned char *readbuffer = g_new0(unsigned char, 4 * len);
721 size_t count = fread(readbuffer, sizeof(unsigned char), 4 * len, str->file_pointer);
722 /* If there was an incomplete character */
726 g_warning("%s: Incomplete character in binary Unicode file.", __func__);
730 for(foo = 0; foo < count; foo += 4)
731 buf[foo / 4] = readbuffer[foo] << 24
732 | readbuffer[foo + 1] << 16
733 | readbuffer[foo + 2] << 8
734 | readbuffer[foo + 3];
736 str->read_count += count / 4;
739 else /* Regular binary file */
741 unsigned char *readbuffer = g_new0(unsigned char, len);
742 size_t count = fread(readbuffer, sizeof(unsigned char), len, str->file_pointer);
744 for(foo = 0; foo < count; foo++)
745 buf[foo] = readbuffer[foo];
747 str->read_count += count;
751 else /* Text mode is the same for Unicode and regular files */
753 /* Do it character-by-character */
755 for(foo = 0; foo < len; foo++)
757 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
766 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
772 * glk_get_line_stream:
773 * @str: An input stream.
774 * @buf: A buffer with space for at least @len characters.
775 * @len: The number of characters to read, plus one.
777 * Reads characters from @str, until either
779 * <alt>@len - 1</alt>
780 * <mathphrase>@len - 1</mathphrase>
782 * characters have been read or a newline has been read. It then puts a
783 * terminal null (<code>'\0'</code>) aracter on
784 * the end. It returns the number of characters actually read, including the
785 * newline (if there is one) but not including the terminal null.
787 * Returns: The number of characters actually read.
790 glk_get_line_stream(strid_t str, char *buf, glui32 len)
792 g_return_val_if_fail(str != NULL, 0);
793 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
794 g_return_val_if_fail(buf != NULL, 0);
798 case STREAM_TYPE_MEMORY:
803 /* Do it character-by-character */
804 while(copycount < len - 1 && str->ubuffer && str->mark < str->buflen)
806 glui32 ch = str->ubuffer[str->mark++];
807 /* Check for Unicode newline; slightly different than
809 if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
811 buf[copycount++] = '\n';
816 if(str->ubuffer[str->mark] == 0x0A)
817 str->mark++; /* skip past next newline */
818 buf[copycount++] = '\n';
821 buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
823 buf[copycount] = '\0';
827 if(str->buffer) /* if not, copycount stays 0 */
828 copycount = MIN(len - 1, str->buflen - str->mark);
829 char *endptr = memccpy(buf, str->buffer + str->mark, '\n', copycount);
830 if(endptr) /* newline was found */
831 copycount = endptr - buf; /* Real copy count */
832 buf[copycount] = '\0';
833 str->mark += copycount;
836 str->read_count += copycount;
839 case STREAM_TYPE_FILE:
842 if(str->unicode) /* Binary file with 4-byte characters */
844 /* Do it character-by-character */
846 for(foo = 0; foo < len - 1; foo++)
848 glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
855 if(is_unicode_newline(ch, str->file_pointer, FALSE))
861 buf[foo] = (ch > 0xFF)? '?' : (char)ch;
866 else /* Regular binary file */
868 fgets(buf, len, str->file_pointer);
869 str->read_count += strlen(buf);
873 else /* Text mode is the same for Unicode and regular files */
875 /* Do it character-by-character */
877 for(foo = 0; foo < len - 1; foo++)
879 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
886 if(is_unicode_newline(ch, str->file_pointer, TRUE))
892 buf[foo] = (ch > 0xFF)? 0x3F : (char)ch;
898 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
904 * glk_get_line_stream_uni:
905 * @str: An input stream.
906 * @buf: A buffer with space for at least @len Unicode code points.
907 * @len: The number of characters to read, plus one.
909 * Reads Unicode characters from @str, until either
911 * <alt>@len - 1</alt>
912 * <mathphrase>@len - 1</mathphrase>
914 * Unicode characters have been read or a newline has been read. It then puts a
915 * terminal null (a zero value) on the end.
917 * Returns: The number of characters actually read, including the newline (if
918 * there is one) but not including the terminal null.
921 glk_get_line_stream_uni(strid_t str, glui32 *buf, glui32 len)
923 g_return_val_if_fail(str != NULL, 0);
924 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
925 g_return_val_if_fail(buf != NULL, 0);
929 case STREAM_TYPE_MEMORY:
934 /* Do it character-by-character */
935 while(copycount < len - 1 && str->ubuffer && str->mark < str->buflen)
937 glui32 ch = str->ubuffer[str->mark++];
938 /* Check for Unicode newline; slightly different than
940 if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
942 buf[copycount++] = '\n';
947 if(str->ubuffer[str->mark] == 0x0A)
948 str->mark++; /* skip past next newline */
949 buf[copycount++] = '\n';
952 buf[copycount++] = ch;
954 buf[copycount] = '\0';
958 /* No recourse to memccpy(), so do it character-by-character */
959 while(copycount < len - 1 && str->buffer && str->mark < str->buflen)
961 gchar ch = str->buffer[str->mark++];
962 /* Check for newline */
963 if(ch == '\n') /* Also check for \r and \r\n? */
965 buf[copycount++] = '\n';
968 buf[copycount++] = (unsigned char)ch;
973 str->read_count += copycount;
976 case STREAM_TYPE_FILE:
979 if(str->unicode) /* Binary file with 4-byte characters */
981 /* Do it character-by-character */
983 for(foo = 0; foo < len - 1; foo++)
985 glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
992 if(is_unicode_newline(ch, str->file_pointer, FALSE))
994 buf[foo] = ch; /* Preserve newline types??? */
1003 else /* Regular binary file */
1005 gchar *readbuffer = g_new0(gchar, len);
1006 fgets(readbuffer, len, str->file_pointer);
1007 glui32 count = strlen(readbuffer) + 1; /* Copy terminator */
1009 for(foo = 0; foo < count; foo++)
1010 buf[foo] = (unsigned char)(readbuffer[foo]);
1011 str->read_count += count;
1015 else /* Text mode is the same for Unicode and regular files */
1017 /* Do it character-by-character */
1019 for(foo = 0; foo < len - 1; foo++)
1021 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
1028 if(is_unicode_newline(ch, str->file_pointer, TRUE))
1030 buf[foo] = ch; /* Preserve newline types??? */
1040 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
1047 **************** SEEKING FUNCTIONS ********************************************
1052 * glk_stream_get_position:
1053 * @str: A file or memory stream.
1055 * Returns the position of the read/write mark in @str. For memory streams and
1056 * binary file streams, this is exactly the number of characters read or written
1057 * from the beginning of the stream (unless you have moved the mark with
1058 * glk_stream_set_position().) For text file streams, matters are more
1059 * ambiguous, since (for example) writing one byte to a text file may store more
1060 * than one character in the platform's native encoding. You can only be sure
1061 * that the position increases as you read or write to the file.
1063 * Additional complication: for Latin-1 memory and file streams, a character is
1064 * a byte. For Unicode memory and file streams (those created by
1065 * glk_stream_open_file_uni() and glk_stream_open_memory_uni()), a character is
1066 * a 32-bit word. So in a binary Unicode file, positions are multiples of four
1070 * If this bothers you, don't use binary Unicode files. I don't think they're
1071 * good for much anyhow.
1074 * Returns: position of the read/write mark in @str.
1077 glk_stream_get_position(strid_t str)
1079 g_return_val_if_fail(str != NULL, 0);
1083 case STREAM_TYPE_MEMORY:
1085 case STREAM_TYPE_FILE:
1086 return ftell(str->file_pointer);
1088 g_warning("%s: Seeking not supported on this type of stream.",
1095 * glk_stream_set_position:
1096 * @str: A file or memory stream.
1097 * @pos: The position to set the mark to, relative to @seekmode.
1098 * @seekmode: One of #seekmode_Start, #seekmode_Current, or #seekmode_End.
1100 * Sets the position of the read/write mark in @str. The position is controlled
1101 * by @pos, and the meaning of @pos is controlled by @seekmode. See the
1102 * <code>seekmode_</code> constants below.
1104 * It is illegal to specify a position before the beginning or after the end of
1107 * In binary files, the mark position is exact — it corresponds with the
1108 * number of characters you have read or written. In text files, this mapping
1109 * can vary, because of linefeed conventions or other character-set
1110 * approximations. See <link linkend="chimara-Streams">Streams</link>.
1111 * glk_stream_set_position() and glk_stream_get_position() measure positions in
1112 * the platform's native encoding — after character cookery. Therefore,
1113 * in a text stream, it is safest to use glk_stream_set_position() only to move
1114 * to the beginning or end of a file, or to a position determined by
1115 * glk_stream_get_position().
1117 * Again, in Latin-1 streams, characters are bytes. In Unicode streams,
1118 * characters are 32-bit words, or four bytes each.
1121 glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode)
1123 g_return_if_fail(str != NULL);
1124 g_return_if_fail(!(seekmode == seekmode_Start && pos < 0));
1125 g_return_if_fail(!(seekmode == seekmode_End || pos > 0));
1129 case STREAM_TYPE_MEMORY:
1132 case seekmode_Start: str->mark = pos; break;
1133 case seekmode_Current: str->mark += pos; break;
1134 case seekmode_End: str->mark = str->buflen + pos; break;
1136 g_assert_not_reached();
1140 case STREAM_TYPE_FILE:
1145 case seekmode_Start: whence = SEEK_SET; break;
1146 case seekmode_Current: whence = SEEK_CUR; break;
1147 case seekmode_End: whence = SEEK_END; break;
1149 g_assert_not_reached();
1152 fseek(str->file_pointer, pos, whence);
1156 g_warning("%s: Seeking not supported on this type of stream.", __func__);