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 * Prints one character @ch to the stream @str. It is illegal for @str to be
283 * %NULL, or an input-only stream.
286 glk_put_char_stream(strid_t str, unsigned char ch)
288 g_return_if_fail(str != NULL);
289 g_return_if_fail(str->file_mode != filemode_Read);
291 write_buffer_to_stream(str, (gchar *)&ch, 1);
295 * glk_put_char_stream_uni:
296 * @str: An output stream.
297 * @ch: A Unicode code point.
299 * Prints one character @ch to the stream @str. It is illegal for @str to be
300 * %NULL, or an input-only stream.
303 glk_put_char_stream_uni(strid_t str, glui32 ch)
305 g_return_if_fail(str != NULL);
306 g_return_if_fail(str->file_mode != filemode_Read);
308 write_buffer_to_stream_uni(str, &ch, 1);
312 * glk_put_string_stream:
313 * @str: An output stream.
314 * @s: A null-terminated string in Latin-1 encoding.
316 * Prints @s to the stream @str. It is illegal for @str to be %NULL, or an
320 glk_put_string_stream(strid_t str, char *s)
322 g_return_if_fail(str != NULL);
323 g_return_if_fail(str->file_mode != filemode_Read);
325 write_buffer_to_stream(str, s, strlen(s));
329 * glk_put_string_stream_uni:
330 * @str: An output stream.
331 * @s: A null-terminated array of Unicode code points.
333 * Prints @s to the stream @str. It is illegal for @str to be %NULL, or an
337 glk_put_string_stream_uni(strid_t str, glui32 *s)
339 g_return_if_fail(str != NULL);
340 g_return_if_fail(str->file_mode != filemode_Read);
342 /* An impromptu strlen() for glui32 arrays */
347 write_buffer_to_stream_uni(str, s, len);
351 * glk_put_buffer_stream:
352 * @str: An output stream.
353 * @buf: An array of characters in Latin-1 encoding.
354 * @len: Length of @buf.
356 * Prints @buf to the stream @str. It is illegal for @str to be %NULL, or an
360 glk_put_buffer_stream(strid_t str, char *buf, glui32 len)
362 g_return_if_fail(str != NULL);
363 g_return_if_fail(str->file_mode != filemode_Read);
365 write_buffer_to_stream(str, buf, len);
369 * glk_put_buffer_stream_uni:
370 * @str: An output stream.
371 * @buf: An array of Unicode code points.
372 * @len: Length of @buf.
374 * Prints @buf to the stream @str. It is illegal for @str to be %NULL, or an
378 glk_put_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len)
380 g_return_if_fail(str != NULL);
381 g_return_if_fail(str->file_mode != filemode_Read);
383 write_buffer_to_stream_uni(str, buf, len);
388 **************** READING FUNCTIONS ********************************************
392 /* Internal function: Read one big-endian four-byte character from file fp and
393 return it as a Unicode code point, or -1 on EOF */
395 read_ucs4be_char_from_file(FILE *fp)
397 unsigned char readbuffer[4];
398 if(fread(readbuffer, sizeof(unsigned char), 4, fp) < 4)
401 readbuffer[0] << 24 |
402 readbuffer[1] << 16 |
407 /* Internal function: Read one UTF-8 character, which may be more than one byte,
408 from file fp and return it as a Unicode code point, or -1 on EOF */
410 read_utf8_char_from_file(FILE *fp)
412 gchar readbuffer[4] = {0, 0, 0, 0}; /* Max UTF-8 width */
414 gunichar charresult = (gunichar)-2;
415 for(foo = 0; foo < 4 && charresult == (gunichar)-2; foo++)
420 readbuffer[foo] = (gchar)ch;
421 charresult = g_utf8_get_char_validated(readbuffer, foo + 1);
422 /* charresult is -1 if invalid, -2 if incomplete, and the unicode code
425 /* Silently return unknown characters as 0xFFFD, Replacement Character */
426 if(charresult == (gunichar)-1 || charresult == (gunichar)-2)
431 /* Internal function: Tell whether this code point is a Unicode newline. The
432 file pointer and eight-bit flag are included in case the newline is a CR
433 (U+000D). If the next character is LF (U+000A) then it also belongs to the
436 is_unicode_newline(glsi32 ch, FILE *fp, gboolean utf8)
438 if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
441 glsi32 ch2 = utf8? read_utf8_char_from_file(fp) :
442 read_ucs4be_char_from_file(fp);
444 fseek(fp, utf8? -1 : -4, SEEK_CUR);
450 /* Internal function: Read one character from a stream. Returns a value which
451 can be returned unchanged by glk_get_char_stream_uni(), but
452 glk_get_char_stream() must replace high values by the placeholder character. */
454 get_char_stream_common(strid_t str)
458 case STREAM_TYPE_MEMORY:
461 if(!str->ubuffer || str->mark >= str->buflen)
463 glui32 ch = str->ubuffer[str->mark++];
469 if(!str->buffer || str->mark >= str->buflen)
471 unsigned char ch = str->buffer[str->mark++];
477 case STREAM_TYPE_FILE:
482 glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
488 else /* Regular file */
490 int ch = fgetc(str->file_pointer);
498 else /* Text mode is the same for Unicode and regular files */
500 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
508 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
514 * glk_get_char_stream:
515 * @str: An input stream.
517 * Reads one character from the stream @str. (There is no notion of a ``current
518 * input stream.'') It is illegal for @str to be %NULL, or an output-only
521 * The result will be between 0 and 255. As with all basic text functions, Glk
522 * assumes the Latin-1 encoding. If the end of the stream has been reached, the
523 * result will be -1. Note that high-bit characters (128..255) are
524 * <emphasis>not</emphasis> returned as negative numbers.
526 * If the stream contains Unicode data --- for example, if it was created with
527 * glk_stream_open_file_uni() or glk_stream_open_memory_uni() --- then
528 * characters beyond 255 will be returned as 0x3F ("?").
530 * Returns: A character value between 0 and 255, or -1 on end of stream.
533 glk_get_char_stream(strid_t str)
535 g_return_val_if_fail(str != NULL, -1);
536 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, -1);
538 glsi32 ch = get_char_stream_common(str);
539 return (ch > 0xFF)? PLACEHOLDER : ch;
543 * glk_get_char_stream_uni:
544 * @str: An input stream.
546 * Reads one character from the stream @str. The result will be between 0 and
547 * 0x7FFFFFFF. If the end of the stream has been reached, the result will be -1.
549 * Returns: A character value between 0 and 255, or -1 on end of stream.
552 glk_get_char_stream_uni(strid_t str)
554 g_return_val_if_fail(str != NULL, -1);
555 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, -1);
557 return get_char_stream_common(str);
561 * glk_get_buffer_stream:
562 * @str: An input stream.
563 * @buf: A buffer with space for at least @len characters.
564 * @len: The number of characters to read.
566 * Reads @len characters from @str, unless the end of stream is reached first.
567 * No terminal null is placed in the buffer.
569 * Returns: The number of characters actually read.
572 glk_get_buffer_stream(strid_t str, char *buf, glui32 len)
574 g_return_val_if_fail(str != NULL, 0);
575 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
576 g_return_val_if_fail(buf != NULL, 0);
580 case STREAM_TYPE_MEMORY:
585 while(copycount < len && str->ubuffer && str->mark < str->buflen)
587 glui32 ch = str->ubuffer[str->mark++];
588 buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
593 if(str->buffer) /* if not, copycount stays 0 */
594 copycount = MIN(len, str->buflen - str->mark);
595 memmove(buf, str->buffer + str->mark, copycount);
596 str->mark += copycount;
599 str->read_count += copycount;
602 case STREAM_TYPE_FILE:
605 if(str->unicode) /* Binary file with 4-byte characters */
607 /* Read len characters of 4 bytes each */
608 unsigned char *readbuffer = g_new0(unsigned char, 4 * len);
609 size_t count = fread(readbuffer, sizeof(unsigned char), 4 * len, str->file_pointer);
610 /* If there was an incomplete character */
614 g_warning("%s: Incomplete character in binary Unicode file.", __func__);
618 for(foo = 0; foo < count; foo += 4)
620 glsi32 ch = readbuffer[foo] << 24
621 | readbuffer[foo + 1] << 16
622 | readbuffer[foo + 2] << 8
623 | readbuffer[foo + 3];
624 buf[foo / 4] = (ch > 255)? 0x3F : (char)ch;
627 str->read_count += count / 4;
630 else /* Regular binary file */
632 size_t count = fread(buf, sizeof(char), len, str->file_pointer);
633 str->read_count += count;
637 else /* Text mode is the same for Unicode and regular files */
639 /* Do it character-by-character */
641 for(foo = 0; foo < len; foo++)
643 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
647 buf[foo] = (ch > 0xFF)? 0x3F : (gchar)ch;
652 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
658 * glk_get_buffer_stream_uni:
659 * @str: An input stream.
660 * @buf: A buffer with space for at least @len Unicode code points.
661 * @len: The number of characters to read.
663 * Reads @len Unicode characters from @str, unless the end of stream is reached
664 * first. No terminal null is placed in the buffer.
666 * Returns: The number of Unicode characters actually read.
669 glk_get_buffer_stream_uni(strid_t str, glui32 *buf, glui32 len)
671 g_return_val_if_fail(str != NULL, 0);
672 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
673 g_return_val_if_fail(buf != NULL, 0);
677 case STREAM_TYPE_MEMORY:
682 if(str->ubuffer) /* if not, copycount stays 0 */
683 copycount = MIN(len, str->buflen - str->mark);
684 memmove(buf, str->ubuffer + str->mark, copycount * 4);
685 str->mark += copycount;
689 while(copycount < len && str->buffer && str->mark < str->buflen)
691 unsigned char ch = str->buffer[str->mark++];
692 buf[copycount++] = ch;
696 str->read_count += copycount;
699 case STREAM_TYPE_FILE:
702 if(str->unicode) /* Binary file with 4-byte characters */
704 /* Read len characters of 4 bytes each */
705 unsigned char *readbuffer = g_new0(unsigned char, 4 * len);
706 size_t count = fread(readbuffer, sizeof(unsigned char), 4 * len, str->file_pointer);
707 /* If there was an incomplete character */
711 g_warning("%s: Incomplete character in binary Unicode file.", __func__);
715 for(foo = 0; foo < count; foo += 4)
716 buf[foo / 4] = readbuffer[foo] << 24
717 | readbuffer[foo + 1] << 16
718 | readbuffer[foo + 2] << 8
719 | readbuffer[foo + 3];
721 str->read_count += count / 4;
724 else /* Regular binary file */
726 unsigned char *readbuffer = g_new0(unsigned char, len);
727 size_t count = fread(readbuffer, sizeof(unsigned char), len, str->file_pointer);
729 for(foo = 0; foo < count; foo++)
730 buf[foo] = readbuffer[foo];
732 str->read_count += count;
736 else /* Text mode is the same for Unicode and regular files */
738 /* Do it character-by-character */
740 for(foo = 0; foo < len; foo++)
742 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
751 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
757 * glk_get_line_stream:
758 * @str: An input stream.
759 * @buf: A buffer with space for at least @len characters.
760 * @len: The number of characters to read, plus one.
762 * Reads characters from @str, until either @len - 1 characters have been read
763 * or a newline has been read. It then puts a terminal null ('\0') aracter on
764 * the end. It returns the number of characters actually read, including the
765 * newline (if there is one) but not including the terminal null.
767 * It is usually more efficient to read several characters at once with
768 * glk_get_buffer_stream() or glk_get_line_stream(), as opposed to calling
769 * glk_get_char_stream() several times.
771 * Returns: The number of characters actually read.
774 glk_get_line_stream(strid_t str, char *buf, glui32 len)
776 g_return_val_if_fail(str != NULL, 0);
777 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
778 g_return_val_if_fail(buf != NULL, 0);
782 case STREAM_TYPE_MEMORY:
787 /* Do it character-by-character */
788 while(copycount < len - 1 && str->ubuffer && str->mark < str->buflen)
790 glui32 ch = str->ubuffer[str->mark++];
791 /* Check for Unicode newline; slightly different than
793 if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
795 buf[copycount++] = '\n';
800 if(str->ubuffer[str->mark] == 0x0A)
801 str->mark++; /* skip past next newline */
802 buf[copycount++] = '\n';
805 buf[copycount++] = (ch > 0xFF)? '?' : (char)ch;
807 buf[copycount] = '\0';
811 if(str->buffer) /* if not, copycount stays 0 */
812 copycount = MIN(len - 1, str->buflen - str->mark);
813 char *endptr = memccpy(buf, str->buffer + str->mark, '\n', copycount);
814 if(endptr) /* newline was found */
815 copycount = endptr - buf; /* Real copy count */
816 buf[copycount] = '\0';
817 str->mark += copycount;
820 str->read_count += copycount;
823 case STREAM_TYPE_FILE:
826 if(str->unicode) /* Binary file with 4-byte characters */
828 /* Do it character-by-character */
830 for(foo = 0; foo < len - 1; foo++)
832 glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
839 if(is_unicode_newline(ch, str->file_pointer, FALSE))
845 buf[foo] = (ch > 0xFF)? '?' : (char)ch;
850 else /* Regular binary file */
852 fgets(buf, len, str->file_pointer);
853 str->read_count += strlen(buf);
857 else /* Text mode is the same for Unicode and regular files */
859 /* Do it character-by-character */
861 for(foo = 0; foo < len - 1; foo++)
863 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
870 if(is_unicode_newline(ch, str->file_pointer, TRUE))
876 buf[foo] = (ch > 0xFF)? 0x3F : (char)ch;
882 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
888 * glk_get_line_stream_uni:
889 * @str: An input stream.
890 * @buf: A buffer with space for at least @len Unicode code points.
891 * @len: The number of characters to read, plus one.
893 * Reads Unicode characters from @str, until either @len - 1 Unicode characters
894 * have been read or a newline has been read. It then puts a terminal null (a
895 * zero value) on the end.
897 * Returns: The number of characters actually read, including the newline (if
898 * there is one) but not including the terminal null.
901 glk_get_line_stream_uni(strid_t str, glui32 *buf, glui32 len)
903 g_return_val_if_fail(str != NULL, 0);
904 g_return_val_if_fail(str->file_mode == filemode_Read || str->file_mode == filemode_ReadWrite, 0);
905 g_return_val_if_fail(buf != NULL, 0);
909 case STREAM_TYPE_MEMORY:
914 /* Do it character-by-character */
915 while(copycount < len - 1 && str->ubuffer && str->mark < str->buflen)
917 glui32 ch = str->ubuffer[str->mark++];
918 /* Check for Unicode newline; slightly different than
920 if(ch == 0x0A || ch == 0x85 || ch == 0x0C || ch == 0x2028 || ch == 0x2029)
922 buf[copycount++] = '\n';
927 if(str->ubuffer[str->mark] == 0x0A)
928 str->mark++; /* skip past next newline */
929 buf[copycount++] = '\n';
932 buf[copycount++] = ch;
934 buf[copycount] = '\0';
938 /* No recourse to memccpy(), so do it character-by-character */
939 while(copycount < len - 1 && str->buffer && str->mark < str->buflen)
941 gchar ch = str->buffer[str->mark++];
942 /* Check for newline */
943 if(ch == '\n') /* Also check for \r and \r\n? */
945 buf[copycount++] = '\n';
948 buf[copycount++] = (unsigned char)ch;
953 str->read_count += copycount;
956 case STREAM_TYPE_FILE:
959 if(str->unicode) /* Binary file with 4-byte characters */
961 /* Do it character-by-character */
963 for(foo = 0; foo < len - 1; foo++)
965 glsi32 ch = read_ucs4be_char_from_file(str->file_pointer);
972 if(is_unicode_newline(ch, str->file_pointer, FALSE))
974 buf[foo] = ch; /* Preserve newline types??? */
983 else /* Regular binary file */
985 gchar *readbuffer = g_new0(gchar, len);
986 fgets(readbuffer, len, str->file_pointer);
987 glui32 count = strlen(readbuffer) + 1; /* Copy terminator */
989 for(foo = 0; foo < count; foo++)
990 buf[foo] = (unsigned char)(readbuffer[foo]);
991 str->read_count += count;
995 else /* Text mode is the same for Unicode and regular files */
997 /* Do it character-by-character */
999 for(foo = 0; foo < len - 1; foo++)
1001 glsi32 ch = read_utf8_char_from_file(str->file_pointer);
1008 if(is_unicode_newline(ch, str->file_pointer, TRUE))
1010 buf[foo] = ch; /* Preserve newline types??? */
1020 g_warning("%s: Reading from this kind of stream unsupported.", __func__);
1027 **************** SEEKING FUNCTIONS ********************************************
1032 * glk_stream_get_position:
1033 * @str: A file or memory stream.
1035 * Returns the position of the read/write mark in @str. For memory streams and
1036 * binary file streams, this is exactly the number of characters read or written
1037 * from the beginning of the stream (unless you have moved the mark with
1038 * glk_stream_set_position().) For text file streams, matters are more
1039 * ambiguous, since (for example) writing one byte to a text file may store more
1040 * than one character in the platform's native encoding. You can only be sure
1041 * that the position increases as you read or write to the file.
1043 * Additional complication: for Latin-1 memory and file streams, a character is
1044 * a byte. For Unicode memory and file streams (those created by
1045 * glk_stream_open_file_uni() and glk_stream_open_memory_uni()), a character is
1046 * a 32-bit word. So in a binary Unicode file, positions are multiples of four
1049 * Returns: position of the read/write mark in @str.
1052 glk_stream_get_position(strid_t str)
1054 g_return_val_if_fail(str != NULL, 0);
1058 case STREAM_TYPE_MEMORY:
1060 case STREAM_TYPE_FILE:
1061 return ftell(str->file_pointer);
1063 g_warning("%s: Seeking not supported on this type of stream.",
1070 * glk_stream_set_position:
1071 * @str: A file or memory stream.
1072 * @pos: The position to set the mark to, relative to @seekmode.
1073 * @seekmode: One of #seekmode_Start, #seekmode_Current, or #seekmode_End.
1075 * Sets the position of the read/write mark in @str. The position is controlled
1076 * by @pos, and the meaning of @pos is controlled by @seekmode:
1078 * <listitem>#seekmode_Start: @pos characters after the beginning of the file.
1080 * <listitem>#seekmode_Current: @pos characters after the current position
1081 * (moving backwards if @pos is negative.)</listitem>
1082 * <listitem>#seekmode_End: @pos characters after the end of the file. (@pos
1083 * should always be zero or negative, so that this will move backwards to a
1084 * position within the file.</listitem>
1086 * It is illegal to specify a position before the beginning or after the end of
1089 * In binary files, the mark position is exact --- it corresponds with the
1090 * number of characters you have read or written. In text files, this mapping
1091 * can vary, because of linefeed conventions or other character-set
1092 * approximations. glk_stream_set_position() and glk_stream_get_position()
1093 * measure positions in the platform's native encoding --- after character
1094 * cookery. Therefore, in a text stream, it is safest to use
1095 * glk_stream_set_position() only to move to the beginning or end of a file, or
1096 * to a position determined by glk_stream_get_position().
1098 * Again, in Latin-1 streams, characters are bytes. In Unicode streams,
1099 * characters are 32-bit words, or four bytes each.
1102 glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekmode)
1104 g_return_if_fail(str != NULL);
1105 g_return_if_fail(!(seekmode == seekmode_Start && pos < 0));
1106 g_return_if_fail(!(seekmode == seekmode_End || pos > 0));
1110 case STREAM_TYPE_MEMORY:
1113 case seekmode_Start: str->mark = pos; break;
1114 case seekmode_Current: str->mark += pos; break;
1115 case seekmode_End: str->mark = str->buflen + pos; break;
1117 g_assert_not_reached();
1121 case STREAM_TYPE_FILE:
1126 case seekmode_Start: whence = SEEK_SET; break;
1127 case seekmode_Current: whence = SEEK_CUR; break;
1128 case seekmode_End: whence = SEEK_END; break;
1130 g_assert_not_reached();
1133 fseek(str->file_pointer, pos, whence);
1137 g_warning("%s: Seeking not supported on this type of stream.", __func__);