Jun 29 13:36:39 2001 Owen Taylor <otaylor@redhat.com>
authorOwen Taylor <otaylor@src.gnome.org>
Sat, 30 Jun 2001 15:22:13 +0000 (15:22 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Sat, 30 Jun 2001 15:22:13 +0000 (15:22 +0000)
        * glib/gstring.[ch] (g_string_set_size): Add function to
        allow setting the length of a string greater than the
        current length (for buffering usage)

        * glib/gstring.[ch]: Expose string->allocated_len, since
        that is useful when using GString simply as a buffer.
        (Renamed from string->alloc)

        * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
        Major patch from Hidetoshi Tajima and Ron Steinke
        reworking GIOChannel to have:

         - Buffering
         - Sane and useful error reporting
         - Streaming encoding conversion with iconv
         - Convenience functions to read by lines or
           an entire file.

        Also fix remaining 64 bit cleanliness issues.

        * tests/iochannel-test.c tests/Makefile.am: Test case
        for IO channel streaming conversion. Still needs
        some fixing up.

22 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/reference/glib/glib-sections.txt
docs/reference/glib/tmpl/glib-unused.sgml
docs/reference/glib/tmpl/iochannels.sgml
docs/reference/glib/tmpl/strings.sgml
glib.def
glib/giochannel.c
glib/giochannel.h
glib/giounix.c
glib/giowin32.c
glib/glib.def
glib/gstring.c
glib/gstring.h
tests/Makefile.am
tests/iochannel-test.c [new file with mode: 0644]

index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index f299664d3e98700f56b2bb17e6bba789b4a27736..d4fdcaca7f1bee7a6421422f06a0280c1db62f65 100644 (file)
@@ -1,3 +1,29 @@
+Fri Jun 29 13:36:39 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * glib/gstring.[ch] (g_string_set_size): Add function to 
+       allow setting the length of a string greater than the 
+       current length (for buffering usage)
+
+       * glib/gstring.[ch]: Expose string->allocated_len, since
+       that is useful when using GString simply as a buffer. 
+       (Renamed from string->alloc)
+
+       * glib/giochannel.[ch] glib/giounix.c glib/giowin32.c:
+       Major patch from Hidetoshi Tajima and Ron Steinke
+       reworking GIOChannel to have:
+
+        - Buffering
+        - Sane and useful error reporting
+        - Streaming encoding conversion with iconv
+        - Convenience functions to read by lines or 
+          an entire file.
+
+       Also fix remaining 64 bit cleanliness issues.
+
+       * tests/iochannel-test.c tests/Makefile.am: Test case
+       for IO channel streaming conversion. Still needs 
+       some fixing up.
+
 Thu Jun 28 16:57:44 2001  Tim Janik  <timj@gtk.org>
 
        * configure.in (GLIB_MICRO_VERSION): up version number to 1.3.7,
index 0d377f5da8900e52d1bbcb233d1c021a3b35eb17..80a06622008c65ca964d6316790348d36e0b892b 100644 (file)
@@ -589,18 +589,29 @@ GIOChannel
 g_io_channel_unix_new
 g_io_channel_unix_get_fd
 
-
 <SUBSECTION>
 g_io_channel_init
 
 <SUBSECTION>
-g_io_channel_read
-GIOError
-g_io_channel_write
-g_io_channel_seek
+g_io_channel_new_file
+GIOFileMode
+g_io_channel_read_chars
+g_io_channel_read_line
+g_io_channel_read_line_string
+g_io_channel_read_to_end
+g_io_channel_write_chars
+g_io_channel_flush
+g_io_channel_seek_position
 GSeekType
 g_io_channel_close
 
+<SUBSECTION>
+GChannelStatus
+GChannelError
+G_CHANNEL_ERROR
+g_channel_error_quark
+g_channel_error_from_errno
+
 <SUBSECTION>
 g_io_channel_ref
 g_io_channel_unref
@@ -615,6 +626,23 @@ GIOFunc
 <SUBSECTION>
 GIOFuncs
 
+<SUBSECTION>
+g_io_channel_get_buffer_size
+g_io_channel_set_buffer_size
+g_io_channel_get_buffer_condition
+g_io_channel_get_flags
+g_io_channel_set_flags
+GIOFlags
+g_io_channel_get_line_term
+g_io_channel_set_line_term
+G_IO_CHANNEL_UNIX_LINE_TERM
+G_IO_CHANNEL_DOS_LINE_TERM
+G_IO_CHANNEL_MACINTOSH_LINE_TERM
+G_IO_CHANNEL_DEFAULT_LINE_TERM
+g_io_channel_get_encoding
+g_io_channel_set_encoding
+G_IO_CHANNEL_ENCODE_RAW
+
 <SUBSECTION Private>
 g_io_channel_win32_new_fd
 g_io_channel_win32_new_messages
@@ -622,6 +650,12 @@ g_io_channel_win32_new_socket
 g_io_channel_win32_poll
 g_io_channel_win32_make_pollfd
 g_io_channel_win32_get_fd
+<SUBSECTION>
+g_io_channel_read
+GIOError
+g_io_channel_write
+g_io_channel_seek
 </SECTION>
 
 <SECTION>
@@ -1395,6 +1429,7 @@ g_string_insert_c
 g_string_insert_len
 g_string_erase
 g_string_truncate
+g_string_set_size
 g_string_free
 
 <SUBSECTION>
index 9c46c7d5d08d5cc6cb3d18ea4e9c5dbc9ee5da43..37c0779fb6fd105c94cb3df36bb100404c7afb2f 100644 (file)
@@ -1,3 +1,37 @@
+<!-- ##### ENUM GChannelError ##### -->
+<para>
+
+</para>
+
+@G_CHANNEL_ERROR_ACCES: 
+@G_CHANNEL_ERROR_BADF: 
+@G_CHANNEL_ERROR_DEADLK: 
+@G_CHANNEL_ERROR_FAULT: 
+@G_CHANNEL_ERROR_INVAL: 
+@G_CHANNEL_ERROR_IO: 
+@G_CHANNEL_ERROR_ISDIR: 
+@G_CHANNEL_ERROR_MFILE: 
+@G_CHANNEL_ERROR_NOLCK: 
+@G_CHANNEL_ERROR_NOSPC: 
+@G_CHANNEL_ERROR_PERM: 
+@G_CHANNEL_ERROR_PIPE: 
+@G_CHANNEL_ERROR_SPIPE: 
+@G_CHANNEL_ERROR_ENCODE_RW: 
+@G_CHANNEL_ERROR_FAILED: 
+
+<!-- ##### ENUM GChannelStatus ##### -->
+<para>
+
+</para>
+
+@G_CHANNEL_STATUS_NORMAL: 
+@G_CHANNEL_STATUS_EOF: 
+@G_CHANNEL_STATUS_PARTIAL_CHARS: 
+@G_CHANNEL_STATUS_AGAIN: 
+@G_CHANNEL_STATUS_INTR: 
+@G_CHANNEL_STATUS_ERROR: 
+@G_CHANNEL_STATUS_BAD_INPUT: 
+
 <!-- ##### USER_FUNCTION GCompareFuncData ##### -->
 <para>
 
 @hook_list: 
 @hook: 
 
+<!-- ##### MACRO G_CHANNEL_ERROR ##### -->
+<para>
+
+</para>
+
+
 <!-- ##### MACRO G_HOOK_DEFERRED_DESTROY ##### -->
 <para>
 
 </para>
 
 
+<!-- ##### MACRO G_IO_CHANNEL_DEFAULT_LINE_TERM ##### -->
+<para>
+One of %G_IO_CHANNEL_UNIX_LINE_TERM, %G_IO_CHANNEL_DOS_LINE_TERM,
+or %G_IO_CHANNEL_MACINTOSH_LINE_TERM (unimplemented)
+depending on the system type.
+</para>
+
+
 <!-- ##### MACRO access ##### -->
 <para>
 
index 6e99a9b48d654fc0d69ef6ba4042c2bd12eae990..c8e84f5ce776dfcedbe81e383846ff0d86cd286e 100644 (file)
@@ -15,11 +15,13 @@ Windows is only partially complete.
 <para>
 To create a new #GIOChannel on Unix systems use g_io_channel_unix_new().
 This works for plain file descriptors, pipes and sockets.
+Alternately, a channel can be created for a file in a system independent
+manner using g_io_channel_new_file().
 </para>
 <para>
 Once a #GIOChannel has been created, it can be used in a generic manner
-with the functions g_io_channel_read(), g_io_channel_write(),
-g_io_channel_seek(), and g_io_channel_close().
+with the functions g_io_channel_read_chars(), g_io_channel_write_chars(),
+g_io_channel_seek_position(), and g_io_channel_close().
 </para>
 <para>
 To add a #GIOChannel to the 
@@ -32,7 +34,8 @@ called whenever these events occur.
 #GIOChannel instances are created with an initial reference count of 1.
 g_io_channel_ref() and g_io_channel_unref() can be used to increment or
 decrement the reference count respectively. When the reference count falls
-to 0, the #GIOChannel is freed. (Though it isn't closed automatically.)
+to 0, the #GIOChannel is freed. (Though it isn't closed automatically,
+unless it was created using g_io_channel_new_from_file().)
 Using g_io_add_watch() or g_io_add_watch_full() increments a channel's
 reference count.
 </para>
@@ -43,6 +46,14 @@ which creates a #GIOChannel from a file descriptor and adds it to the
 The event source can later be removed with gtk_input_remove().
 Similar functions can also be found in GDK.
 </para>
+<para>
+The new functions g_io_channel_read_chars(), g_io_channel_read_line(),
+g_io_channel_read_line_string(), g_io_channel_read_to_end(),
+g_io_channel_write_chars(), g_io_channel_seek_position(),
+and g_io_channel_flush() should not be mixed with the
+depricated functions g_io_channel_read(), g_io_channel_write(),
+and g_io_channel_seek() on the same channel.
+</para>
 
 <!-- ##### SECTION See_Also ##### -->
 <para>
@@ -69,6 +80,21 @@ private and should only be accessed with the following functions.
 @channel_flags: 
 @ref_count: 
 @funcs: 
+@encoding: 
+@read_cd: 
+@write_cd: 
+@line_term: 
+@buf_size: 
+@read_buf: 
+@encoded_read_buf: 
+@write_buf: 
+@use_buffer: 
+@do_encode: 
+@ready_to_read: 
+@ready_to_write: 
+@close_on_unref: 
+@seekable_cached: 
+@is_seekable: 
 
 <!-- ##### FUNCTION g_io_channel_unix_new ##### -->
 <para>
@@ -102,59 +128,120 @@ programmer (unless you are creating a new type of #GIOChannel).
 @channel: a #GIOChannel.
 
 
-<!-- ##### FUNCTION g_io_channel_read ##### -->
+<!-- ##### FUNCTION g_io_channel_new_file ##### -->
 <para>
-Reads data from a #GIOChannel.
 </para>
 
-@channel: a #GIOChannel.
-@buf: a buffer to read the data into (which should be at least count bytes
-long).
-@count: the number of bytes to read from the #GIOChannel.
-@bytes_read: returns the number of bytes actually read.
-@Returns: %G_IO_ERROR_NONE if the operation was successful.
+@filename: 
+@mode: 
+@error: 
+@Returns: 
 
 
-<!-- ##### ENUM GIOError ##### -->
+<!-- ##### ENUM GIOFileMode ##### -->
 <para>
 
 </para>
 
-@G_IO_ERROR_NONE: 
-@G_IO_ERROR_AGAIN: 
-@G_IO_ERROR_INVAL: 
-@G_IO_ERROR_UNKNOWN: 
+@G_IO_FILE_MODE_READ: 
+@G_IO_FILE_MODE_WRITE: 
+@G_IO_FILE_MODE_APPEND: 
+@G_IO_FILE_MODE_READ_WRITE: 
+@G_IO_FILE_MODE_READ_WRITE_TRUNCATE: 
+@G_IO_FILE_MODE_READ_WRITE_APPEND: 
 
-<!-- ##### FUNCTION g_io_channel_write ##### -->
+<!-- ##### FUNCTION g_io_channel_read_chars ##### -->
+<para>
+
+</para>
+
+@channel: 
+@buf: 
+@count: 
+@bytes_read: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_read_line ##### -->
 <para>
-Writes data to a #GIOChannel.
+
 </para>
 
-@channel: a #GIOChannel.
-@buf: the buffer containing the data to write.
-@count: the number of bytes to write.
-@bytes_written: the number of bytes actually written.
-@Returns: %G_IO_ERROR_NONE if the operation was successful.
+@channel: 
+@str_return: 
+@length: 
+@terminator_pos: 
+@error: 
+@Returns: 
 
 
-<!-- ##### FUNCTION g_io_channel_seek ##### -->
+<!-- ##### FUNCTION g_io_channel_read_line_string ##### -->
 <para>
-Sets the current position in the #GIOChannel, similar to the standard system
-call <function>fseek()</function>.
+
 </para>
 
-@channel: a #GIOChannel.
-@offset: an offset, in bytes, which is added to the position specified by
-@type.
-@type: the position in the file, which can be %G_SEEK_CUR (the current
-position), %G_SEEK_SET (the start of the file), or %G_SEEK_END (the end of the
-file).
-@Returns: %G_IO_ERROR_NONE if the operation was successful.
+@channel: 
+@buffer: 
+@terminator_pos: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_read_to_end ##### -->
+<para>
+
+</para>
+
+@channel: 
+@str_return: 
+@length: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_write_chars ##### -->
+<para>
+
+</para>
+
+@channel: 
+@buf: 
+@count: 
+@bytes_written: 
+@error: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_flush ##### -->
+<para>
+
+</para>
+
+@channel: 
+@error: 
+@Returns: 
+<!-- # Unused Parameters # -->
+@err: 
+
+
+<!-- ##### FUNCTION g_io_channel_seek_position ##### -->
+<para>
+
+</para>
+
+@channel: 
+@offset: 
+@type: 
+@error: 
+@Returns: 
+<!-- # Unused Parameters # -->
+@err: 
 
 
 <!-- ##### ENUM GSeekType ##### -->
 <para>
-An enumeration specifying the base position for a g_io_channel_seek()
+An enumeration specifying the base position for a g_io_channel_seek_position()
 operation.
 
 <informaltable pgwide=1 frame="none" role="enum">
@@ -186,11 +273,26 @@ operation.
 
 <!-- ##### FUNCTION g_io_channel_close ##### -->
 <para>
-Closes a #GIOChannel.
-The #GIOChannel will be freed when its reference count drops to 0.
 </para>
 
-@channel: a #GIOChannel.
+@channel: 
+
+
+<!-- ##### FUNCTION g_channel_error_quark ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION g_channel_error_from_errno ##### -->
+<para>
+
+</para>
+
+@en: 
+@Returns: 
 
 
 <!-- ##### FUNCTION g_io_channel_ref ##### -->
@@ -330,4 +432,182 @@ generic way.
 @io_close: 
 @io_create_watch: 
 @io_free: 
+@io_set_flags: 
+@io_get_flags: 
+
+<!-- ##### FUNCTION g_io_channel_get_buffer_size ##### -->
+<para>
+
+</para>
+
+@channel: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_set_buffer_size ##### -->
+<para>
+
+</para>
+
+@channel: 
+@size: 
+
+
+<!-- ##### FUNCTION g_io_channel_get_buffer_condition ##### -->
+<para>
+
+</para>
+
+@channel: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_get_flags ##### -->
+<para>
+
+</para>
+
+@channel: 
+@Returns: 
+<!-- # Unused Parameters # -->
+@flags: 
+@error: 
+
+
+<!-- ##### FUNCTION g_io_channel_set_flags ##### -->
+<para>
+
+</para>
+
+@channel: 
+@flags: 
+@error: 
+@Returns: 
+
+
+<!-- ##### ENUM GIOFlags ##### -->
+<para>
+
+</para>
+
+@G_IO_FLAG_APPEND: 
+@G_IO_FLAG_NONBLOCK: 
+@G_IO_FLAG_IS_READABLE: 
+@G_IO_FLAG_IS_WRITEABLE: 
+@G_IO_FLAG_IS_SEEKABLE: 
+@G_IO_FLAG_MASK: 
+@G_IO_FLAG_GET_MASK: 
+@G_IO_FLAG_SET_MASK: 
+
+<!-- ##### FUNCTION g_io_channel_get_line_term ##### -->
+<para>
+
+</para>
+
+@channel: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_set_line_term ##### -->
+<para>
+
+</para>
+
+@channel: 
+@line_term: 
+
+
+<!-- ##### MACRO G_IO_CHANNEL_UNIX_LINE_TERM ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO G_IO_CHANNEL_DOS_LINE_TERM ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### MACRO G_IO_CHANNEL_MACINTOSH_LINE_TERM ##### -->
+<para>
+
+</para>
+
+
+
+<!-- ##### FUNCTION g_io_channel_get_encoding ##### -->
+<para>
+
+</para>
+
+@channel: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_set_encoding ##### -->
+<para>
+
+</para>
+
+@channel: 
+@encoding: 
+@error: 
+@Returns: 
+
+
+<!-- ##### MACRO G_IO_CHANNEL_ENCODE_RAW ##### -->
+<para>
+Encoding for nonbuffered IO. With this encoding, data must be
+read using g_io_channel_read_chars(); the other functions will
+not work.
+</para>
+
+
+
+<!-- ##### FUNCTION g_io_channel_read ##### -->
+<para>
+</para>
+
+@channel: 
+@buf: 
+@count: 
+@bytes_read: 
+@Returns: 
+
+
+<!-- ##### ENUM GIOError ##### -->
+<para>
+#GIOError is only used by the depricated functions g_io_channel_read(),
+g_io_channel_write(), and g_io_channel_seek().
+</para>
+
+@G_IO_ERROR_NONE: 
+@G_IO_ERROR_AGAIN: 
+@G_IO_ERROR_INVAL: 
+@G_IO_ERROR_UNKNOWN: 
+
+<!-- ##### FUNCTION g_io_channel_write ##### -->
+<para>
+</para>
+
+@channel: 
+@buf: 
+@count: 
+@bytes_written: 
+@Returns: 
+
+
+<!-- ##### FUNCTION g_io_channel_seek ##### -->
+<para>
+</para>
+
+@channel: 
+@offset: 
+@type.
+@type: 
+@Returns: 
+
 
index 2e64a19d89bd4ddb06dacca22825c8c687e631b8..1c435d2ed87953cf709acb3b906d38bbcf8690ca 100644 (file)
@@ -32,6 +32,7 @@ string.
 
 @str: 
 @len: 
+@alloc: 
 
 <!-- ##### FUNCTION g_string_new ##### -->
 <para>
@@ -247,6 +248,16 @@ Cuts off the end of the GString, leaving the first @len characters.
 @Returns: the #GString.
 
 
+<!-- ##### FUNCTION g_string_set_size ##### -->
+<para>
+
+</para>
+
+@string: 
+@len: 
+@Returns: 
+
+
 <!-- ##### FUNCTION g_string_free ##### -->
 <para>
 Frees the memory allocated for the #GString.
index 89f4467fbca13cb55a15400ed1419dad3a6b7aa7..51448f3cabcbb36577cfc21e747741ca9f84075f 100644 (file)
--- a/glib.def
+++ b/glib.def
@@ -51,6 +51,8 @@ EXPORTS
        g_cache_new
        g_cache_remove
        g_cache_value_foreach
+       g_channel_error_quark
+       g_channel_error_from_errno
        g_clear_error
        g_completion_add_items
        g_completion_clear_items
@@ -184,10 +186,26 @@ EXPORTS
        g_io_add_watch
        g_io_add_watch_full
        g_io_channel_close
+       g_io_channel_flush
+       g_io_channel_get_buffer_condition
+       g_io_channel_get_buffer_size
+       g_io_channel_get_encoding
+       g_io_channel_get_flags
+       g_io_channel_get_line_term
        g_io_channel_init
+       g_io_channel_new_file
        g_io_channel_read
+       g_io_channel_read_chars
+       g_io_channel_read_line
+       g_io_channel_read_line_string
+       g_io_channel_read_to_end
        g_io_channel_ref
        g_io_channel_seek
+       g_io_channel_seek_position
+       g_io_channel_set_buffer_size
+       g_io_channel_set_encoding
+       g_io_channel_set_flags
+       g_io_channel_set_line_term
        g_io_channel_unix_get_fd
        g_io_channel_unix_new
        g_io_channel_unref
@@ -200,6 +218,7 @@ EXPORTS
        g_io_channel_win32_poll
        g_io_channel_win32_set_debug
        g_io_channel_write
+       g_io_channel_write_chars
        g_io_create_watch
        g_list_alloc
        g_list_append
index a4d09b740865a00a57e5220bb246e51dd2e8edae..d6b7bd32d3880fe6c9195415439b9e8704913572 100644 (file)
  * MT safe
  */
 
-#include "config.h"
+#include <string.h>
+#include <errno.h>
 
-#include "glib.h"
+#include "config.h"
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
+#undef G_DISABLE_DEPRECATED
+
+#include "glib.h"
+
+#include "glibintl.h"
+
+#define G_IO_NICE_BUF_SIZE     1024
+
+static GIOError                g_io_error_get_from_g_error     (GIOStatus status,
+                                                        GError      *err);
+static void            g_io_channel_purge              (GIOChannel  *channel);
+static GIOStatus       g_io_channel_fill_buffer        (GIOChannel  *channel,
+                                                        GError     **err);
+
 void
 g_io_channel_init (GIOChannel *channel)
 {
   channel->channel_flags = 0;
   channel->ref_count = 1;
+  channel->encoding = NULL;
+  channel->line_term = NULL;
+  channel->buf_size = G_IO_NICE_BUF_SIZE;
+  channel->read_buf = g_string_sized_new (G_IO_NICE_BUF_SIZE);
+  channel->encoded_read_buf = NULL; /* Allocate if we get an encoding */
+  channel->write_buf = g_string_sized_new (G_IO_NICE_BUF_SIZE);
+  channel->use_buffer = TRUE;
+  channel->do_encode = FALSE;
+  channel->ready_to_read = TRUE;
+  channel->ready_to_write = TRUE;
+  channel->close_on_unref = FALSE;
+  channel->seekable_cached = FALSE;
 }
 
-
 void 
 g_io_channel_ref (GIOChannel *channel)
 {
@@ -61,47 +87,296 @@ g_io_channel_unref (GIOChannel *channel)
 
   channel->ref_count--;
   if (channel->ref_count == 0)
-    channel->funcs->io_free (channel);
+    {
+      if (channel->close_on_unref)
+        g_io_channel_close (channel);
+      else
+        g_io_channel_purge (channel);
+      g_free (channel->encoding);
+      if (channel->do_encode)
+        {
+          g_iconv_close (channel->read_cd);
+          g_iconv_close (channel->write_cd);
+          g_string_free (channel->encoded_read_buf, TRUE);
+        }
+      g_free (channel->line_term);
+      g_string_free (channel->read_buf, TRUE);
+      g_string_free (channel->write_buf, TRUE);
+      channel->funcs->io_free (channel);
+    }
 }
 
+static GIOError
+g_io_error_get_from_g_error (GIOStatus status,
+                            GError *err)
+{
+  switch (status)
+    {
+      case G_IO_STATUS_NORMAL:
+      case G_IO_STATUS_EOF:
+        return G_IO_ERROR_NONE;
+      case G_IO_STATUS_AGAIN:
+        return G_IO_ERROR_AGAIN;
+      case G_IO_STATUS_ERROR:
+        if (err->domain != G_IO_CHANNEL_ERROR)
+          return G_IO_ERROR_UNKNOWN;
+        switch (err->code)
+          {
+            case G_IO_CHANNEL_ERROR_INVAL:
+              return G_IO_ERROR_INVAL;
+            default:
+              return G_IO_ERROR_UNKNOWN;
+          }
+      default:
+        g_assert_not_reached ();
+        return G_IO_ERROR_UNKNOWN; /* Keep the compiler happy */
+    }
+}
+
+/**
+ * g_io_channel_read:
+ * @channel: a #GIOChannel. 
+ * @buf: a buffer to read the data into (which should be at least count bytes long).
+ * @count: the number of bytes to read from the #GIOChannel.
+ * @bytes_read: returns the number of bytes actually read. 
+ * 
+ * Reads data from a #GIOChannel. This function is depricated. New code should
+ * use g_io_channel_read_chars() instead.
+ * 
+ * Return value: %G_IO_ERROR_NONE if the operation was successful. 
+ **/
 GIOError 
 g_io_channel_read (GIOChannel *channel, 
                   gchar      *buf, 
-                  guint       count,
-                  guint      *bytes_read)
+                  gsize       count,
+                  gsize      *bytes_read)
 {
+  GError *err = NULL;
+  GIOError error;
+  GIOStatus status;
+
   g_return_val_if_fail (channel != NULL, G_IO_ERROR_UNKNOWN);
+  g_return_val_if_fail (bytes_read != NULL, G_IO_ERROR_UNKNOWN);
+
+  status = channel->funcs->io_read (channel, buf, count, bytes_read, &err);
 
-  return channel->funcs->io_read (channel, buf, count, bytes_read);
+  error = g_io_error_get_from_g_error (status, err);
+
+  if (err)
+    g_error_free (err);
+
+  return error;
 }
 
+/**
+ * g_io_channel_write:
+ * @channel:  a #GIOChannel.
+ * @buf: the buffer containing the data to write. 
+ * @count: the number of bytes to write.
+ * @bytes_written:  the number of bytes actually written.
+ * 
+ * Writes data to a #GIOChannel. This function is depricated. New code should
+ * use g_io_channel_write_chars() instead.
+ * 
+ * Return value:  %G_IO_ERROR_NONE if the operation was successful.
+ **/
 GIOError 
-g_io_channel_write (GIOChannel *channel, 
-                   gchar      *buf, 
-                   guint       count,
-                   guint      *bytes_written)
+g_io_channel_write (GIOChannel  *channel, 
+                   const gchar *buf, 
+                   gsize        count,
+                   gsize       *bytes_written)
 {
+  GError *err = NULL;
+  GIOError error;
+  GIOStatus status;
+
   g_return_val_if_fail (channel != NULL, G_IO_ERROR_UNKNOWN);
+  g_return_val_if_fail (bytes_written != NULL, G_IO_ERROR_UNKNOWN);
+
+  status = channel->funcs->io_write (channel, buf, count, bytes_written, &err);
+
+  error = g_io_error_get_from_g_error (status, err);
 
-  return channel->funcs->io_write (channel, buf, count, bytes_written);
+  if (err)
+    g_error_free (err);
+
+  return error;
 }
 
+/**
+ * g_io_channel_seek:
+ * @channel: a #GIOChannel. 
+ * @offset: an offset, in bytes, which is added to the position specified by @type
+ * @type: the position in the file, which can be %G_SEEK_CUR (the current
+ *        position), %G_SEEK_SET (the start of the file), or %G_SEEK_END (the end of the
+ *        file).
+ * 
+ * Sets the current position in the #GIOChannel, similar to the standard library
+ * function fseek(). This function is depricated. New code should
+ * use g_io_channel_seek_position() instead.
+ * 
+ * Return value: %G_IO_ERROR_NONE if the operation was successful.
+ **/
 GIOError 
 g_io_channel_seek  (GIOChannel   *channel,
-                   gint        offset, 
-                   GSeekType   type)
+                   glong         offset, 
+                   GSeekType     type)
 {
+  GError *err = NULL;
+  GIOError error;
+  GIOStatus status;
+
   g_return_val_if_fail (channel != NULL, G_IO_ERROR_UNKNOWN);
 
-  return channel->funcs->io_seek (channel, offset, type);
+  switch (type)
+    {
+      case G_SEEK_CUR:
+      case G_SEEK_SET:
+      case G_SEEK_END:
+        break;
+      default:
+        g_warning ("g_io_channel_seek: unknown seek type");
+        return G_IO_ERROR_UNKNOWN;
+    }
+
+  status = channel->funcs->io_seek (channel, offset, type, &err);
+
+  error = g_io_error_get_from_g_error (status, err);
+
+  if (err)
+    g_error_free (err);
+
+  return error;
 }
-     
+
+/* The function g_io_channel_new_file() is prototyped in both
+ * giounix.c and giowin32.c, so we stick its documentation here.
+ */
+
+/**
+ * g_io_channel_new_file:
+ * @filename: A string containing the name of a file.
+ * @mode: A #GIOFileMode
+ * @error: A location to return an error of type %G_IO_CHANNEL_ERROR.
+ *
+ * Open a file @filename as a #GIOChannel using mode @mode. This
+ * channel will be closed when the last reference to it is dropped,
+ * so there is no need to call g_io_channel_close() (though doing
+ * so will not cause problems, as long as no attempt is made to
+ * access the channel after it is closed).
+ *
+ * Return value: A #GIOChannel on success, %NULL on failure.
+ **/
+
+/**
+ * g_io_channel_close:
+ * @channel: A #GIOChannel
+ * 
+ * Close an IO channel. Any pending data to be written will be
+ * flushed, ignoring errors. The channel will not be freed until the
+ * last reference is dropped using g_io_channel_unref(). This
+ * function is deprecated: you should use g_io_channel_shutdown()
+ * instead.
+ **/
 void
 g_io_channel_close (GIOChannel *channel)
 {
+  GError *err = NULL;
+  
   g_return_if_fail (channel != NULL);
 
-  channel->funcs->io_close (channel);
+  g_io_channel_purge (channel);
+
+  channel->funcs->io_close (channel, &err);
+
+  if (err)
+    { /* No way to return the error */
+      g_warning ("Error closing channel: %s", err->message);
+      g_error_free (err);
+    }
+  
+  channel->close_on_unref = FALSE; /* Because we already did */
+  channel->ready_to_read = FALSE;
+  channel->ready_to_write = FALSE;
+}
+
+/**
+ * g_io_channel_shutdown:
+ * @channel: a #GIOChannel
+ * @flush: if %TRUE, flush pending
+ * @err: location to store a #GIOChannelError
+ * 
+ * Close an IO channel. Any pending data to be written will be
+ * flushed. The channel will not be freed until the
+ * last reference is dropped using g_io_channel_unref().
+ **/
+GIOStatus
+g_io_channel_shutdown (GIOChannel *channel,
+                      gboolean    flush,
+                      GError     **err)
+{
+  GIOStatus status;
+  GIOStatus result = G_IO_STATUS_NORMAL;
+  
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+
+  if (flush && channel->write_buf->len > 0)
+    {
+      GIOFlags flags;
+      
+      /* Set the channel to blocking, to avoid a busy loop
+       */
+      flags = g_io_channel_get_flags (channel);
+      status = g_io_channel_set_flags (channel, flags & ~G_IO_FLAG_NONBLOCK, NULL);
+      if (status != G_IO_STATUS_NORMAL)
+       result = G_IO_STATUS_ERROR; 
+      
+      g_io_channel_flush (channel, err);
+    }
+
+  status = channel->funcs->io_close (channel, err && *err ? NULL : err);
+  if (status != G_IO_STATUS_NORMAL)
+    result = G_IO_STATUS_ERROR; 
+
+  channel->close_on_unref = FALSE; /* Because we already did */
+  channel->ready_to_read = FALSE;
+  channel->ready_to_write = FALSE;
+
+  return result;
+}
+
+/* This function is used for the final flush on close or unref */
+static void
+g_io_channel_purge (GIOChannel *channel)
+{
+  GError *err = NULL;
+
+  g_return_if_fail (channel != NULL);
+
+  if (channel->write_buf->len > 0)
+    {
+      GIOFlags flags;
+      
+      /* Set the channel to blocking, to avoid a busy loop
+       */
+      flags = g_io_channel_get_flags (channel);
+      g_io_channel_set_flags (channel, flags & ~G_IO_FLAG_NONBLOCK, NULL);
+
+      g_io_channel_flush (channel, &err);
+
+      if (err)
+       { /* No way to return the error */
+         g_warning ("Error flushing string: %s", err->message);
+         g_error_free (err);
+       }
+    }
+
+  /* Flush these in case anyone tries to close without unrefing */
+
+  g_string_truncate (channel->read_buf, 0);
+  if (channel->do_encode)
+    g_string_truncate (channel->encoded_read_buf, 0);
+  g_string_truncate (channel->write_buf, 0);
 }
 
 GSource *
@@ -146,3 +421,1154 @@ g_io_add_watch (GIOChannel    *channel,
 {
   return g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, condition, func, user_data, NULL);
 }
+
+/**
+ * g_io_channel_get_buffer_condition:
+ * @channel: A #GIOChannel
+ *
+ * This function returns a #GIOCondition depending on the status of the
+ * internal buffers in the #GIOChannel. Only the flags %G_IO_IN and
+ * %G_IO_OUT may be set.
+ *
+ * Return value: A #GIOCondition
+ **/
+GIOCondition
+g_io_channel_get_buffer_condition (GIOChannel *channel)
+{
+  return (((channel->read_buf->len > 0) || (channel->encoded_read_buf->len > 0))
+    ? G_IO_IN : 0) & ((channel->write_buf->len > 0) ? G_IO_OUT : 0);
+}
+
+/**
+ * g_channel_error_from_errno:
+ * @en: An errno error number, e.g. EINVAL
+ *
+ * Return value: A #GIOChannelError error number, e.g. %G_IO_CHANNEL_ERROR_INVAL
+ **/
+GIOChannelError
+g_channel_error_from_errno (gint en)
+{
+#ifdef EAGAIN
+  g_return_val_if_fail (en != EAGAIN, G_IO_CHANNEL_ERROR_FAILED);
+#endif
+#ifdef EINTR
+  g_return_val_if_fail (en != EINTR, G_IO_CHANNEL_ERROR_FAILED);
+#endif
+
+  switch (en)
+    {
+#ifdef EACCES
+    case EACCES:
+      return G_IO_CHANNEL_ERROR_ACCES;
+#endif
+
+#ifdef EBADF
+    case EBADF:
+      return G_IO_CHANNEL_ERROR_BADF;
+#endif
+
+#ifdef EFAULT
+    case EFAULT:
+      return G_IO_CHANNEL_ERROR_FAULT;
+#endif
+
+#ifdef EINVAL
+    case EINVAL:
+      return G_IO_CHANNEL_ERROR_INVAL;
+#endif
+
+#ifdef EIO
+    case EIO:
+      return G_IO_CHANNEL_ERROR_IO;
+#endif
+
+#ifdef EISDIR
+    case EISDIR:
+      return G_IO_CHANNEL_ERROR_ISDIR;
+#endif
+
+#ifdef EMFILE
+    case EMFILE:
+      return G_IO_CHANNEL_ERROR_MFILE;
+#endif
+
+#ifdef ENOLCK
+    case ENOLCK:
+      return G_IO_CHANNEL_ERROR_NOLCK;
+#endif
+
+#ifdef ENOSPC
+    case ENOSPC:
+      return G_IO_CHANNEL_ERROR_NOSPC;
+#endif
+
+#ifdef EPERM
+    case EPERM:
+      return G_IO_CHANNEL_ERROR_PERM;
+#endif
+      
+#ifdef EPIPE
+    case EPIPE:
+      return G_IO_CHANNEL_ERROR_PIPE;
+#endif
+
+#ifdef ESPIPE
+    case ESPIPE:
+      return G_IO_CHANNEL_ERROR_SPIPE;
+#endif
+
+    default:
+      return G_IO_CHANNEL_ERROR_FAILED;
+    }
+}
+
+/**
+ * g_io_channel_set_buffer_size:
+ * @channel: a #GIOChannel
+ * @size: the size of the buffer. 0 == pick a good size
+ *
+ * Set the buffer size.
+ **/  
+void
+g_io_channel_set_buffer_size (GIOChannel       *channel,
+                              gsize             size)
+{
+  g_return_if_fail (channel != NULL);
+
+  if (size == 0)
+    size = G_IO_NICE_BUF_SIZE;
+
+  channel->buf_size = size;
+}
+
+/**
+ * g_io_channel_get_buffer_size:
+ * @channel: a #GIOChannel
+ *
+ * Get the buffer size.
+ *
+ * Return value: the size of the buffer.
+ **/  
+gsize
+g_io_channel_get_buffer_size (GIOChannel       *channel)
+{
+  g_return_val_if_fail (channel != NULL, 0);
+
+  return channel->buf_size;
+}
+
+/**
+ * g_io_channel_set_line_term:
+ * @channel: a #GIOChannel
+ * @line_term: The line termination string. Use %NULL for auto detect.
+ *
+ * This sets the string that #GIOChannel uses to determine
+ * where in the file a line break occurs.
+ **/
+void
+g_io_channel_set_line_term (GIOChannel *channel,
+                            const gchar        *line_term)
+{
+  g_return_if_fail (channel != NULL);
+  g_return_if_fail (!line_term || line_term[0]); /* Disallow "" */
+
+  g_free (channel->line_term);
+  channel->line_term = g_strdup (line_term);
+}
+
+/**
+ * g_io_channel_get_line_term:
+ * @channel: a #GIOChannel
+ *
+ * This returns the string that #GIOChannel uses to determine
+ * where in the file a line break occurs. A value of %NULL
+ * indicates auto detection.
+ *
+ * Return value: The line termination string. This value
+ *   is owned by GLib and must not be freed.
+ **/
+G_CONST_RETURN gchar*
+g_io_channel_get_line_term (GIOChannel *channel)
+{
+  g_return_val_if_fail (channel != NULL, 0);
+
+  return channel->line_term;
+}
+
+/**
+ * g_io_channel_set_flags:
+ * @channel: a #GIOChannel
+ * @flags: the flags to set on the channel
+ * @error: A location to return an error of type #GIOChannelError
+ *
+ * Return value:
+ **/
+GIOStatus
+g_io_channel_set_flags (GIOChannel *channel,
+                        GIOFlags    flags,
+                        GError    **error)
+{
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+                       G_IO_STATUS_ERROR);
+
+  return (* channel->funcs->io_set_flags)(channel,
+                                         flags & G_IO_FLAG_SET_MASK,
+                                         error);
+}
+
+/**
+ * g_io_channel_get_flags:
+ * @channel: a #GIOChannel
+ * @flags: the flags which are set on the channel
+ *
+ * Gets the current flags for a #GIOChannel, including read-only
+ * flags such as %G_IO_FLAG_IS_READABLE.
+ **/
+GIOFlags
+g_io_channel_get_flags (GIOChannel *channel)
+{
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+
+  return (* channel->funcs->io_get_flags) (channel);
+}
+
+/**
+ * g_io_channel_seek_position:
+ * @channel: a #GIOChannel
+ * @offset: The offset in bytes from the position specified by @type
+ * @type: a #GSeekType. The type %G_SEEK_CUR is only allowed if
+ *        the channel has the default encoding or the
+ *        encoding %G_IO_CHANNEL_ENCODE_RAW for raw file access.
+ * @error: A location to return an error of type #GIOChannelError
+ *
+ * Replacement for g_io_channel_seek() with the new API.
+ *
+ * Return value:
+ **/
+GIOStatus
+g_io_channel_seek_position     (GIOChannel* channel,
+                                glong       offset,
+                                GSeekType   type,
+                                GError    **error)
+{
+  GIOStatus status;
+
+  /* For files, only one of the read and write buffers can contain data.
+   * For sockets, both can contain data.
+   */
+
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+                       G_IO_STATUS_ERROR);
+
+  switch (type)
+    {
+      case G_SEEK_CUR: /* The user is seeking relative to the head of the buffer */
+        if (channel->do_encode)
+          {
+            g_warning ("Seek type G_SEEK_CUR not allowed for this channel's encoding.\n");
+            return G_IO_STATUS_ERROR;
+          }
+          break;
+      case G_SEEK_SET:
+      case G_SEEK_END:
+        break;
+      default:
+        g_warning ("g_io_channel_seek_position: unknown seek type");
+        return G_IO_STATUS_ERROR;
+    }
+
+  /* Do a quick check for easy failure
+   */
+  if (!channel->seekable_cached)
+    g_io_channel_get_flags (channel);
+
+  g_assert (channel->seekable_cached);
+
+  if (!channel->is_seekable)
+    {
+      g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_SPIPE,
+        _("Seeking not allowed on this type of channel"));
+      return G_IO_STATUS_ERROR;
+    }
+
+  if (channel->use_buffer)
+    {
+      status = g_io_channel_flush (channel, error);
+      if (status != G_IO_STATUS_NORMAL)
+        return status;
+
+      if (type == G_SEEK_CUR)
+        {
+          g_assert (!channel->do_encode);
+          offset -= channel->read_buf->len;
+        }
+    }
+
+
+  status = channel->funcs->io_seek (channel, offset, type, error);
+
+  if ((status == G_IO_STATUS_NORMAL) && (channel->use_buffer))
+    {
+      g_string_erase (channel->read_buf, 0, channel->read_buf->len);
+      g_string_erase (channel->encoded_read_buf, 0, channel->read_buf->len);
+      channel->ready_to_write = TRUE;
+      if (channel->do_encode) /* Conversion state no longer matches position in file */
+        {
+          g_iconv (channel->read_cd, NULL, NULL, NULL, NULL);
+          g_iconv (channel->write_cd, NULL, NULL, NULL, NULL);
+        }
+    }
+
+  return status;
+}
+
+/**
+ * g_io_channel_flush:
+ * @channel: a #GIOChannel
+ * @error: location to store an error of type #GIOChannelError
+ *
+ * Flush the write buffer for the GIOChannel.
+ *
+ * Return value: the status of the operation: One of
+ *   G_IO_CHANNEL_NORMAL, G_IO_CHANNEL_AGAIN, or
+ *   G_IO_CHANNEL_ERROR.
+ **/
+GIOStatus
+g_io_channel_flush (GIOChannel *channel,
+                   GError     **error)
+{
+  GIOStatus status;
+  gsize this_time, bytes_written = 0;
+
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR);
+
+  if (channel->write_buf->len == 0)
+    {
+      channel->ready_to_read = TRUE;
+      return G_IO_STATUS_NORMAL;
+    }
+
+  do
+    {
+      status = channel->funcs->io_write (channel,
+                                      channel->write_buf->str + bytes_written,
+                                      channel->write_buf->len - bytes_written,
+                                      &this_time, error);
+      bytes_written += this_time;
+    }
+  while ((bytes_written < channel->write_buf->len)
+         && (status == G_IO_STATUS_NORMAL)
+         && (this_time > 0)); /* Prevent an infinite loop */
+
+  g_string_erase (channel->write_buf, 0, bytes_written);
+
+  if (status != G_IO_STATUS_NORMAL)
+    return status;
+
+  if (channel->write_buf->len > 0)
+    return G_IO_STATUS_AGAIN;
+
+  channel->ready_to_read = TRUE;
+
+  return G_IO_STATUS_NORMAL;
+}
+
+/**
+ * g_io_channel_set_encoding:
+ * @channel: a #GIOChannel
+ * @encoding: the encoding type
+ * @error: location to store an error of type #GConvertError.
+ *
+ * Set the encoding for the input/output of the channel. The internal
+ * encoding is always UTF-8.
+ *
+ * The encoding %G_IO_CHANNEL_ENCODE_RAW disables encoding and turns
+ * off internal buffering. Data can be read from it only with
+ * g_io_channel_read_chars(). Both %G_IO_CHANNEL_ENCODE_RAW and
+ * the default state (no encoding, but buffered)
+ * are safe to use with binary data.
+ *
+ * Encodings
+ * other than the default and %G_IO_CHANNEL_ENCODE_RAW cannot
+b * use g_io_channel_seek_position() with seek type %G_SEEK_CUR,
+ * and cannot mix reading and writing if the channel is
+ * a file without first doing a seek of type %G_SEEK_SET or
+ * %G_SEEK_END.
+ *
+ * The encoding can only be set under three conditions:
+ *
+ * 1. The channel was just created, and has not been written to
+ *    or read from yet.
+ *
+ * 2. The channel is a file, and the file pointer was just
+ *    repositioned by a call to g_io_channel_seek_position().
+ *    (This flushes all the internal buffers.)
+ *
+ * 3. The current encoding is %G_IO_CHANNEL_ENCODE_RAW.
+ *
+ * Return Value: %G_IO_STATUS_NORMAL if the encoding was succesfully set.
+ **/
+GIOStatus
+g_io_channel_set_encoding (GIOChannel  *channel,
+                           const gchar *encoding,
+                          GError      **error)
+{
+  GIConv read_cd, write_cd;
+  gboolean did_encode;
+
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL), G_IO_STATUS_ERROR);
+
+  /* Make sure the buffers are empty */
+
+  g_return_val_if_fail (channel->read_buf->len == 0, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (channel->write_buf->len == 0, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (channel->encoded_read_buf == NULL ||
+                       channel->encoded_read_buf->len == 0, G_IO_STATUS_ERROR);
+
+  did_encode = channel->do_encode;
+
+  if (!encoding || strcmp (encoding, "UTF8") == 0 || strcmp (encoding, "UTF-8") == 0)
+    {
+      channel->use_buffer = TRUE;
+      channel->do_encode = FALSE;
+      read_cd = write_cd = (GIConv) -1; /* keep the compiler happy */
+    }
+  else if (!strcmp (encoding, G_IO_CHANNEL_ENCODE_RAW))
+    {
+      channel->use_buffer = FALSE;
+      channel->do_encode = FALSE;
+      read_cd = write_cd = (GIConv) -1; /* keep the compiler happy */
+    }
+  else
+    {
+      gint err;
+      const gchar *from_enc, *to_enc;
+
+      read_cd = g_iconv_open ("UTF-8", encoding);
+
+      if (read_cd == (GIConv) -1)
+        {
+          err = errno;
+          from_enc = "UTF-8";
+          to_enc = encoding;
+          write_cd = (GIConv) -1; /* keep the compiler happy */
+        }
+      else
+        {
+          write_cd = g_iconv_open (encoding, "UTF-8");
+          if (write_cd == (GIConv) -1)
+            {
+              err = errno;
+              g_iconv_close (read_cd);
+              from_enc = encoding;
+              to_enc = "UTF-8";
+            }
+          else
+            {
+              err = 0;
+              from_enc = to_enc = NULL; /* Keep the compiler happy */
+            }
+        }
+
+      if (err)
+        {
+          /* Something went wrong.  */
+          if (err == EINVAL)
+            g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_CONVERSION,
+                         _("Conversion from character set `%s' to `%s' is not supported"),
+                         from_enc, to_enc);
+          else
+            g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
+                         _("Could not open converter from `%s' to `%s': %s"),
+                         from_enc, to_enc, strerror (errno));
+          return G_IO_STATUS_ERROR;
+        }
+
+      channel->use_buffer = TRUE;
+      channel->do_encode = TRUE;
+      if (!did_encode)
+        channel->encoded_read_buf = g_string_sized_new (channel->buf_size);
+    }
+
+  /* The encoding is ok, so set the fields in channel */
+
+  if (did_encode)
+    {
+      g_iconv_close (channel->read_cd);
+      g_iconv_close (channel->write_cd);
+      if (!channel->do_encode)
+        {
+          g_string_free (channel->encoded_read_buf, TRUE);
+          channel->encoded_read_buf = NULL;
+        }
+    }
+
+  if (channel->do_encode)
+    {
+      channel->read_cd = read_cd;
+      channel->write_cd = write_cd;
+    }
+
+  g_free (channel->encoding);
+  channel->encoding = g_strdup (encoding);
+
+  return G_IO_STATUS_NORMAL;
+}
+
+/**
+ * g_io_channel_get_encoding:
+ * @channel: a #GIOChannel
+ *
+ * Get the encoding for the input/output of the channel. The internal
+ * encoding is always UTF-8. The encoding %G_IO_CHANNEL_ENCODE_RAW
+ * disables encoding and turns off internal buffering. Both
+ * %G_IO_CHANNEL_ENCODE_RAW and the default (no encoding, but buffered)
+ * are safe to use with binary data.
+ *
+ * Return value: A string containing the encoding, this string is
+ *   owned by GLib and must not be freed.
+ **/
+G_CONST_RETURN gchar*
+g_io_channel_get_encoding (GIOChannel      *channel)
+{
+  g_return_val_if_fail (channel != NULL, NULL);
+
+  return channel->encoding;
+}
+
+static GIOStatus
+g_io_channel_fill_buffer (GIOChannel *channel,
+                          GError    **err)
+{
+  gsize read_size, cur_len, oldlen;
+  GIOStatus status;
+
+  if (!channel->ready_to_read)
+    {
+    status = g_io_channel_flush (channel, err);
+    if (status != G_IO_STATUS_NORMAL)
+      return status;
+    }
+  g_assert (channel->ready_to_read);
+
+  if (!channel->seekable_cached)
+    g_io_channel_get_flags (channel);
+
+  g_assert (channel->seekable_cached);
+
+  if (channel->is_seekable)
+    channel->ready_to_write = FALSE;
+
+  cur_len = channel->read_buf->len;
+
+  g_string_set_size (channel->read_buf, channel->read_buf->len + channel->buf_size);
+
+  status = channel->funcs->io_read (channel, channel->read_buf->str + cur_len,
+                                    channel->buf_size, &read_size, err);
+
+  g_assert ((status == G_IO_STATUS_NORMAL) || (read_size == 0));
+
+  g_string_truncate (channel->read_buf, read_size + cur_len);
+
+  if ((status != G_IO_STATUS_NORMAL)
+    && ((status != G_IO_STATUS_EOF) || (channel->read_buf->len == 0)))
+    return status;
+
+  g_assert (channel->read_buf->len > 0);
+
+  if (channel->do_encode)
+    {
+      size_t errnum, inbytes_left, outbytes_left;
+      gchar *inbuf, *outbuf;
+
+      oldlen = channel->encoded_read_buf->len;
+
+reencode:
+
+      inbytes_left = channel->read_buf->len;
+      outbytes_left = channel->buf_size;
+
+      g_string_set_size (channel->encoded_read_buf, channel->encoded_read_buf->len + outbytes_left);
+
+      inbuf = channel->read_buf->str;
+      outbuf = channel->encoded_read_buf->str + channel->encoded_read_buf->len - outbytes_left;
+
+      errnum = g_iconv (channel->read_cd, &inbuf, &inbytes_left,
+                       &outbuf, &outbytes_left);
+
+      g_string_erase (channel->read_buf, 0,
+                     channel->read_buf->len - inbytes_left);
+      g_string_truncate (channel->encoded_read_buf,
+                        channel->encoded_read_buf->len - outbytes_left);
+
+      if (errnum == (size_t) -1)
+        {
+          switch (errno)
+            {
+              case EINVAL:
+                if ((oldlen == channel->encoded_read_buf->len)
+                  && (status == G_IO_STATUS_EOF))
+                  status = G_IO_STATUS_PARTIAL_CHARS;
+                else
+                  status = G_IO_STATUS_NORMAL;
+                break;
+              case E2BIG:
+                goto reencode;
+              case EILSEQ:
+                if (oldlen < channel->encoded_read_buf->len)
+                  status = G_IO_STATUS_NORMAL;
+                else
+                  {
+                    g_set_error (err, G_CONVERT_ERROR,
+                      G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+                      _("Invalid byte sequence in conversion input"));
+                    return G_IO_STATUS_ERROR;
+                  }
+                break;
+              default:
+                g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
+                  _("Error during conversion: %s"), strerror (errno));
+                return G_IO_STATUS_ERROR;
+            }
+        }
+      if (channel->encoded_read_buf->len == 0)
+        {
+          g_assert (status != G_IO_STATUS_NORMAL);
+          return status;
+        }
+    }
+
+  return status;
+}
+
+/**
+ * g_io_channel_read_line:
+ * @channel: a #GIOChannel
+ * @str_return: The line read from the #GIOChannel, not including the
+ *              line terminator. This data should be freed with g_free()
+ *              when no longer needed. This
+ *              is a null terminated string. If a @length of zero is
+ *              returned, this will be %NULL instead.
+ * @length: location to store length of the read data, or %NULL
+ * @terminator_pos: location to store position of line terminator, or %NULL
+ * @error: A location to return an error of type #GConvertError
+ *         or #GIOChannelError
+ *
+ * Read a line, not including the terminating character(s),
+ * from a #GIOChannel into a newly allocated string.
+ * @length will contain allocated memory if the return
+ * is %G_IO_STATUS_NORMAL.
+ *
+ * Return value: a newly allocated string. Free this string
+ *   with g_free() when you are done with it.
+ **/
+GIOStatus
+g_io_channel_read_line (GIOChannel *channel,
+                        gchar     **str_return,
+                        gsize      *length,
+                       gsize      *terminator_pos,
+                       GError    **error)
+{
+  GIOStatus status;
+  GString *string;
+  
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (str_return != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+                       G_IO_STATUS_ERROR);
+
+  string = g_string_sized_new (channel->buf_size);
+
+  status = g_io_channel_read_line_string (channel, string, terminator_pos, error);
+
+  if (length)
+    *length = string->len;
+
+  if (str_return)
+    *str_return = g_string_free (string, FALSE);
+  else
+    g_string_free (string, TRUE);
+  
+  return status;
+}
+
+/**
+ * g_io_channel_read_line_string:
+ * @channel: a #GIOChannel
+ * @buffer: a #GString into which the line will be written.
+ *          If @buffer already contains data, the new data will
+ *          be appended to it.
+ * @terminator_pos: location to store position of line terminator, or %NULL
+ * @error: a location to store an error of type #GConvertError
+ *         or #GIOChannelError
+ *
+ * Read a line from a #GIOChannel, using a #GString as a buffer.
+ *
+ * Return value:
+ **/
+GIOStatus
+g_io_channel_read_line_string (GIOChannel *channel,
+                               GString   *buffer,
+                              gsize      *terminator_pos,
+                               GError   **error)
+{
+  GIOStatus status;
+  gsize checked_to, line_term_len, line_length;
+  GString *use_buf;
+  gboolean first_time = TRUE;
+
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (buffer != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+                       G_IO_STATUS_ERROR);
+  
+  if (!channel->use_buffer)
+    {
+      /* Can't do a raw read in read_line */
+      g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
+                   _("Can't do a raw read in g_io_channel_read_line_string"));
+      return G_IO_STATUS_ERROR;
+    }
+
+  if (!channel->ready_to_read)
+    {
+      status = g_io_channel_flush (channel, error);
+      if (status != G_IO_STATUS_NORMAL)
+        return status;
+    }
+  g_assert (channel->ready_to_read);
+
+  if (channel->do_encode)
+    use_buf = channel->encoded_read_buf;
+  else
+    use_buf = channel->read_buf;
+
+  status = G_IO_STATUS_NORMAL;
+
+  if (channel->line_term)
+    line_term_len = strlen (channel->line_term);
+  else
+    line_term_len = 2;
+
+  checked_to = 0;
+
+  while (TRUE)
+    {
+      if (!first_time || (use_buf->len == 0))
+        {
+          status = g_io_channel_fill_buffer (channel, error);
+          switch (status)
+            {
+              case G_IO_STATUS_NORMAL:
+                g_assert (use_buf->len > 0);
+                break;
+              case G_IO_STATUS_EOF:
+              case G_IO_STATUS_PARTIAL_CHARS:
+                if (use_buf->len == 0)
+                  return status;
+                break;
+              default:
+                return status;
+            }
+        }
+
+      g_assert (use_buf->len > 0);
+
+      first_time = FALSE;
+
+      if (channel->line_term)
+        {
+          gchar *line_end = strstr (use_buf->str + checked_to, channel->line_term);
+          if (line_end)
+            {
+              line_length = line_end - use_buf->str;
+              break;
+            }
+        }
+      else /* auto detect */
+        {
+          gchar *newline_pos, *linefeed_pos;
+
+          newline_pos = strchr (use_buf->str + checked_to, '\n');
+          linefeed_pos = strchr (use_buf->str + checked_to, '\r');
+
+          g_assert (!newline_pos || !linefeed_pos || (newline_pos != linefeed_pos));
+
+          if (newline_pos && (!linefeed_pos || (linefeed_pos > newline_pos))) /* unix */
+            {
+              line_length = newline_pos - use_buf->str;
+              line_term_len = 1;
+              break;
+            }
+          else if (linefeed_pos &&
+                  (linefeed_pos < use_buf->str + use_buf->len - 1 ||
+                   status == G_IO_STATUS_EOF))
+            {
+              line_length = linefeed_pos - use_buf->str;
+              if (newline_pos && (newline_pos == linefeed_pos + 1)) /* dos */
+                line_term_len = 2;
+              else /* mac */
+               line_term_len = 1;
+              break;
+            }
+        }
+
+      /* Also terminate on '\0' */
+
+      line_length = strlen (use_buf->str);
+      if (line_length < use_buf->len)
+        {
+          line_term_len = 0;
+          break;
+        }
+
+      /* Check for EOF */
+
+      if (status != G_IO_STATUS_NORMAL)
+        {
+          line_length = use_buf->len;
+          line_term_len = 0;
+          break;
+        }
+
+      if (use_buf->len > line_term_len - 1)
+       checked_to = use_buf->len - (line_term_len - 1);
+      else
+       checked_to = 0;
+    }
+
+  g_string_append_len (buffer, use_buf->str, line_length + line_term_len);
+  g_string_erase (use_buf, 0, line_length + line_term_len);
+
+  if (terminator_pos)
+    *terminator_pos = line_length;
+
+  return G_IO_STATUS_NORMAL;
+}
+
+/**
+ * g_io_channel_read_to_end:
+ * @channel: a #GIOChannel
+ * @str_return: Location to store a pointer to a string holding
+ *              the remaining data in the #GIOChannel. This data should
+ *              be freed with g_free() when no longer needed. This
+ *              data is terminated by an extra null, but there may be other
+ *              nulls in the intervening data.
+ * @length: Location to store length of the data
+ * @error: A location to return an error of type #GConvertError
+ *         or #GIOChannelError
+ *
+ * Read all the remaining data from the file. Parameters as
+ * for g_io_channel_read_line.
+ *
+ * Return value: One of #G_IO_STATUS_EOF or #G_IO_STATUS_PARTIAL_CHARS
+ *               on success
+ **/
+GIOStatus
+g_io_channel_read_to_end (GIOChannel   *channel,
+                          gchar        **str_return,
+                          gsize                *length,
+                          GError       **error)
+{
+  GIOStatus status;
+  GString **use_buf;
+    
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (str_return != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (length != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+    G_IO_STATUS_ERROR);
+
+  *str_return = NULL;
+  *length = 0;
+
+  if (!channel->use_buffer)
+    {
+      g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
+                   _("Can't do a raw read in g_io_channel_read_to_end"));
+      return G_IO_STATUS_ERROR;
+    }
+
+  do
+    status = g_io_channel_fill_buffer (channel, error);
+  while (status == G_IO_STATUS_NORMAL);
+
+  if ((status != G_IO_STATUS_EOF)
+    && (status != G_IO_STATUS_PARTIAL_CHARS))
+    return status;
+
+  if (channel->do_encode)
+    use_buf = &channel->encoded_read_buf;
+  else
+    use_buf = &channel->read_buf;
+
+  if (length)
+    *length = (*use_buf)->len;
+
+  if (str_return)
+    *str_return = g_string_free (*use_buf, FALSE);
+  else
+    g_string_free (*use_buf, TRUE);
+  
+  *use_buf = g_string_sized_new (channel->buf_size);
+
+  return status;
+}
+
+/**
+ * g_io_channel_read_chars:
+ * @channel: a #GIOChannel
+ * @buf: a buffer to read data into
+ * @count: the size of the buffer. Note that the buffer may
+ *         not be complelely filled even if there is data
+ *         in the buffer if the remaining data is not a
+ *         complete character.
+ * @bytes_read: The number of bytes read.
+ * @error: A location to return an error of type #GConvertError
+ *         or #GIOChannelError.
+ *
+ * Replacement for g_io_channel_read() with the new API.
+ *
+ * Return value:
+ **/
+GIOStatus
+g_io_channel_read_chars (GIOChannel    *channel,
+                         gchar         *buf,
+                         gsize          count,
+                        gsize          *bytes_read,
+                         GError        **error)
+{
+  GIOStatus status;
+  GString *use_buf;
+
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+                       G_IO_STATUS_ERROR);
+  g_return_val_if_fail (bytes_read != NULL, G_IO_STATUS_ERROR);
+
+  if (count == 0)
+    {
+      *bytes_read = 0;
+      return G_IO_STATUS_NORMAL;
+    }
+  g_return_val_if_fail (buf != NULL, G_IO_STATUS_ERROR);
+
+  if (!channel->use_buffer)
+    {
+      g_assert (channel->ready_to_read);
+      g_assert (channel->read_buf->len == 0);
+
+      return channel->funcs->io_read (channel, buf, count, bytes_read, error);
+    }
+
+  if (!channel->ready_to_read)
+    {
+      status = g_io_channel_flush (channel, error);
+      if (status != G_IO_STATUS_NORMAL)
+        return status;
+    }
+  g_assert (channel->ready_to_read);
+
+  if (channel->do_encode)
+    use_buf = channel->encoded_read_buf;
+  else
+    use_buf = channel->read_buf;
+
+  status = G_IO_STATUS_NORMAL;
+
+  while (use_buf->len < count && status == G_IO_STATUS_NORMAL)
+    {
+      status = g_io_channel_fill_buffer (channel, error);
+    }
+
+  switch (status)
+    {
+    case G_IO_STATUS_NORMAL:
+      g_assert (use_buf->len > 0);
+      break;
+    case G_IO_STATUS_EOF:
+    case G_IO_STATUS_PARTIAL_CHARS:
+      if (use_buf->len == 0)
+       {
+         *bytes_read = 0;
+         return status;
+       }
+      break;
+    default:
+      *bytes_read = 0;
+      return status;
+    }
+
+  *bytes_read = MIN (count, use_buf->len);
+  memcpy (buf, use_buf->str, *bytes_read);
+  g_string_erase (use_buf, 0, *bytes_read);
+
+  return G_IO_STATUS_NORMAL;
+}
+
+/**
+ * g_io_channel_write_chars:
+ * @channel: a #GIOChannel
+ * @buf: a buffer to write data from
+ * @count: the size of the buffer. If -1, the buffer
+ *         is taken to be a nul terminated string.
+ * @bytes_written: The number of bytes written.
+ * @error: A location to return an error of type #GConvertError
+ *         or #GIOChannelError
+ *
+ * Replacement for g_io_channel_write() with the new API.
+ *
+ * Return value: a return value of %G_IO_STATUS_PARTIAL_CHARS
+ *               indicates that @buf contains less than one
+ *               complete UTF-8 character.
+ **/
+GIOStatus
+g_io_channel_write_chars (GIOChannel   *channel,
+                          const gchar  *buf,
+                          gssize        count,
+                         gsize         *bytes_written,
+                          GError       **error)
+{
+  GIOStatus status;
+
+  g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (bytes_written != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail ((error == NULL) || (*error == NULL),
+                       G_IO_STATUS_ERROR);
+
+  if (count < 0)
+    count = strlen (buf);
+  
+  if (count == 0)
+    return G_IO_STATUS_NORMAL;
+
+  g_return_val_if_fail (buf != NULL, G_IO_STATUS_ERROR);
+  g_return_val_if_fail (count > 0, G_IO_STATUS_ERROR);
+
+  /* Raw write case */
+
+  if (!channel->use_buffer)
+    {
+      g_assert (channel->write_buf->len == 0);
+      return channel->funcs->io_write (channel, buf, count, bytes_written, error);
+    }
+
+  /* General case */
+
+  if (channel->write_buf->len == 0)
+    {
+      /* Check to make sure the channel's writeable before we stick
+       * the first data in the buffer.
+       */
+      GIOFlags flags = g_io_channel_get_flags (channel);
+
+      if (!(flags & G_IO_FLAG_IS_WRITEABLE))
+        {
+          /* Mimic a failure of channel->funcs->io_write */
+          g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_BADF,
+                       _("Channel is not writeable"));
+          return G_IO_STATUS_ERROR;
+        }
+    }
+  g_assert (channel->seekable_cached);
+
+  if (!channel->ready_to_write)
+    {
+      if (channel->is_seekable)
+        {
+          if (channel->do_encode)
+            {
+              g_set_error (error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_ENCODE_RW,
+                           _("Mixed reading and writing not allowed on encoded files"));
+              return G_IO_STATUS_ERROR;
+            }
+          status = g_io_channel_seek_position (channel, 0, G_SEEK_CUR, error);
+          if (status != G_IO_STATUS_NORMAL)
+            return status;
+        }
+      channel->ready_to_write = TRUE;
+    }
+
+  if (channel->is_seekable)
+    channel->ready_to_read = FALSE;
+
+  if (!channel->do_encode)
+    {
+      g_string_append_len (channel->write_buf, buf, count);
+      *bytes_written = count;
+    }
+  else
+    {
+      gsize bytes_to_go = count, buf_space, err;
+      gchar *outbuf;
+      gsize oldlen = channel->write_buf->len;
+
+      do
+        {
+         g_string_set_size (channel->write_buf, channel->write_buf->len + channel->buf_size);
+          buf_space = channel->buf_size;
+          outbuf = channel->write_buf->str + channel->write_buf->len - buf_space;
+    
+          err = g_iconv (channel->write_cd, (gchar**) &buf, &bytes_to_go,
+                        &outbuf, &buf_space);
+
+          g_string_truncate (channel->write_buf, channel->write_buf->len - buf_space);
+          *bytes_written = count - bytes_to_go;
+
+          if (err == (size_t) -1)
+            {
+              switch (errno)
+               {
+                  case EINVAL:
+                    if (*bytes_written > 0)
+                      return G_IO_STATUS_NORMAL;
+                    else
+                      return G_IO_STATUS_PARTIAL_CHARS;
+                  case E2BIG:
+                    break;
+                  case EILSEQ:
+                    if (*bytes_written > 0)
+                      return G_IO_STATUS_NORMAL;
+                    else
+                      {
+                        g_set_error (error, G_CONVERT_ERROR,
+                         G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
+                          _("Invalid byte sequence in conversion input"));
+                        return G_IO_STATUS_ERROR;
+                      }
+                  default:
+                    g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
+                      _("Error during conversion: %s"), strerror (errno));
+                    g_string_truncate (channel->write_buf, oldlen);
+                    *bytes_written = 0;
+                    return G_IO_STATUS_ERROR;
+               }
+            }
+        }
+      while (bytes_to_go > 0);
+    }
+
+  if (channel->write_buf->len > channel->buf_size)
+    return g_io_channel_flush (channel, error);
+  else
+    return G_IO_STATUS_NORMAL;
+}
+
+/**
+ * g_channel_error_quark:
+ *
+ * Return value: The quark used as %G_IO_CHANNEL_ERROR
+ **/
+GQuark
+g_channel_error_quark (void)
+{
+  static GQuark q = 0;
+  if (q == 0)
+    q = g_quark_from_static_string ("g-channel-error-quark");
+
+  return q;
+}
index 51b870a7b554b85370c1d73dbab0d6b6eacc6d9c..8f2d3410db55615d936a63cd0201e985d3f6dab3 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <glib/gmain.h>
 #include <glib/gtypes.h>
+#include <glib/gstring.h>
 
 G_BEGIN_DECLS
 
@@ -37,6 +38,7 @@ G_BEGIN_DECLS
 
 typedef struct _GIOChannel     GIOChannel;
 typedef struct _GIOFuncs        GIOFuncs;
+
 typedef enum
 {
   G_IO_ERROR_NONE,
@@ -44,12 +46,46 @@ typedef enum
   G_IO_ERROR_INVAL,
   G_IO_ERROR_UNKNOWN
 } GIOError;
+
+#define G_IO_CHANNEL_ERROR g_channel_error_quark()
+
+typedef enum
+{
+  /* Derived from errno */
+  G_IO_CHANNEL_ERROR_ACCES,
+  G_IO_CHANNEL_ERROR_BADF,
+  G_IO_CHANNEL_ERROR_DEADLK,
+  G_IO_CHANNEL_ERROR_FAULT,
+  G_IO_CHANNEL_ERROR_INVAL,
+  G_IO_CHANNEL_ERROR_IO,
+  G_IO_CHANNEL_ERROR_ISDIR,
+  G_IO_CHANNEL_ERROR_MFILE,
+  G_IO_CHANNEL_ERROR_NOLCK,
+  G_IO_CHANNEL_ERROR_NOSPC,
+  G_IO_CHANNEL_ERROR_PERM,
+  G_IO_CHANNEL_ERROR_PIPE,
+  G_IO_CHANNEL_ERROR_SPIPE,
+  /* Other */
+  G_IO_CHANNEL_ERROR_ENCODE_RW,
+  G_IO_CHANNEL_ERROR_FAILED
+} GIOChannelError;
+
+typedef enum
+{
+  G_IO_STATUS_ERROR,
+  G_IO_STATUS_NORMAL,
+  G_IO_STATUS_EOF,
+  G_IO_STATUS_PARTIAL_CHARS, /* like EOF, but with unconverted data left */
+  G_IO_STATUS_AGAIN
+} GIOStatus;
+
 typedef enum
 {
   G_SEEK_CUR,
   G_SEEK_SET,
   G_SEEK_END
 } GSeekType;
+
 typedef enum
 {
   G_IO_IN      GLIB_SYSDEF_POLLIN,
@@ -60,11 +96,58 @@ typedef enum
   G_IO_NVAL    GLIB_SYSDEF_POLLNVAL
 } GIOCondition;
 
+#define G_IO_CHANNEL_UNIX_LINE_TERM "\n"
+#define G_IO_CHANNEL_DOS_LINE_TERM "\r\n"
+#define G_IO_CHANNEL_MACINTOSH_LINE_TERM "\r"
+#define G_IO_CHANNEL_ENCODE_RAW "GIOChannelEncodeRaw"
+
+typedef enum
+{
+  G_IO_FLAG_APPEND = 1 << 0,
+  G_IO_FLAG_NONBLOCK = 1 << 1,
+  G_IO_FLAG_IS_READABLE = 1 << 2,      /* Read only flag */
+  G_IO_FLAG_IS_WRITEABLE = 1 << 3,     /* Read only flag */
+  G_IO_FLAG_IS_SEEKABLE = 1 << 4,      /* Read only flag */
+  G_IO_FLAG_MASK = (1 << 5) - 1,
+  G_IO_FLAG_GET_MASK = G_IO_FLAG_MASK,
+  G_IO_FLAG_SET_MASK = G_IO_FLAG_APPEND | G_IO_FLAG_NONBLOCK,
+} GIOFlags;
+
+typedef enum
+{
+  G_IO_FILE_MODE_READ,
+  G_IO_FILE_MODE_WRITE,
+  G_IO_FILE_MODE_APPEND,
+  G_IO_FILE_MODE_READ_WRITE,
+  G_IO_FILE_MODE_READ_WRITE_TRUNCATE,
+  G_IO_FILE_MODE_READ_WRITE_APPEND,
+} GIOFileMode;
+
 struct _GIOChannel
 {
   guint channel_flags;
   guint ref_count;
   GIOFuncs *funcs;
+
+  gchar *encoding;
+  GIConv read_cd;
+  GIConv write_cd;
+  gchar *line_term;
+
+  gsize buf_size;
+  GString *read_buf;
+  GString *encoded_read_buf;
+  GString *write_buf;
+
+  /* Group the flags together to save memory */
+
+  gboolean use_buffer : 1;
+  gboolean do_encode : 1;
+  gboolean ready_to_read : 1;
+  gboolean ready_to_write : 1;
+  gboolean close_on_unref : 1;
+  gboolean seekable_cached : 1;
+  gboolean is_seekable : 1;
 };
 
 typedef gboolean (*GIOFunc) (GIOChannel   *source,
@@ -72,50 +155,123 @@ typedef gboolean (*GIOFunc) (GIOChannel   *source,
                             gpointer      data);
 struct _GIOFuncs
 {
-  GIOError  (*io_read)         (GIOChannel   *channel, 
-                               gchar        *buf, 
-                               guint         count,
-                               guint        *bytes_read);
-  GIOError  (*io_write)        (GIOChannel   *channel, 
-                               gchar        *buf, 
-                               guint         count,
-                               guint        *bytes_written);
-  GIOError  (*io_seek)         (GIOChannel   *channel, 
-                               gint          offset, 
-                               GSeekType     type);
-  void      (*io_close)        (GIOChannel   *channel);
-  GSource * (*io_create_watch) (GIOChannel   *channel,
-                               GIOCondition  condition);
-  void      (*io_free)         (GIOChannel   *channel);
+  GIOStatus (*io_read)           (GIOChannel   *channel, 
+                                 gchar        *buf, 
+                                 gsize         count,
+                                 gsize        *bytes_read,
+                                 GError      **err);
+  GIOStatus (*io_write)          (GIOChannel   *channel, 
+                                 const gchar  *buf, 
+                                 gsize         count,
+                                 gsize        *bytes_written,
+                                 GError      **err);
+  GIOStatus (*io_seek)           (GIOChannel   *channel, 
+                                 glong         offset, 
+                                 GSeekType     type,
+                                 GError      **err);
+  GIOStatus  (*io_close)         (GIOChannel   *channel,
+                                 GError      **err);
+  GSource*   (*io_create_watch)  (GIOChannel   *channel,
+                                 GIOCondition  condition);
+  void       (*io_free)          (GIOChannel   *channel);
+  GIOStatus  (*io_set_flags)     (GIOChannel   *channel,
+                                  GIOFlags      flags,
+                                 GError      **err);
+  GIOFlags   (*io_get_flags)     (GIOChannel   *channel);
 };
 
 void        g_io_channel_init   (GIOChannel    *channel);
 void        g_io_channel_ref    (GIOChannel    *channel);
 void        g_io_channel_unref  (GIOChannel    *channel);
+
+#ifndef G_DISABLE_DEPRECATED
 GIOError    g_io_channel_read   (GIOChannel    *channel, 
                                 gchar         *buf, 
-                                guint          count,
-                                guint         *bytes_read);
+                                gsize          count,
+                                gsize         *bytes_read);
 GIOError  g_io_channel_write    (GIOChannel    *channel, 
-                                gchar         *buf, 
-                                guint          count,
-                                guint         *bytes_written);
+                                const gchar   *buf, 
+                                gsize          count,
+                                gsize         *bytes_written);
 GIOError  g_io_channel_seek     (GIOChannel    *channel,
-                                gint           offset, 
+                                glong          offset, 
                                 GSeekType      type);
 void      g_io_channel_close    (GIOChannel    *channel);
-guint     g_io_add_watch_full   (GIOChannel    *channel,
-                                gint           priority,
-                                GIOCondition   condition,
-                                GIOFunc        func,
-                                gpointer       user_data,
-                                GDestroyNotify notify);
-GSource *g_io_create_watch      (GIOChannel   *channel,
-                                GIOCondition  condition);
-guint    g_io_add_watch         (GIOChannel    *channel,
-                                GIOCondition   condition,
-                                GIOFunc        func,
-                                gpointer       user_data);
+#endif /* G_DISABLE_DEPRECATED */
+
+GIOStatus g_io_channel_shutdown (GIOChannel      *channel,
+                                gboolean         flush,
+                                GError         **err);
+guint     g_io_add_watch_full   (GIOChannel      *channel,
+                                gint             priority,
+                                GIOCondition     condition,
+                                GIOFunc          func,
+                                gpointer         user_data,
+                                GDestroyNotify   notify);
+GSource * g_io_create_watch     (GIOChannel      *channel,
+                                GIOCondition     condition);
+guint     g_io_add_watch        (GIOChannel      *channel,
+                                GIOCondition     condition,
+                                GIOFunc          func,
+                                gpointer         user_data);
+
+/* character encoding conversion involved functions.
+ */
+
+void                  g_io_channel_set_buffer_size      (GIOChannel   *channel,
+                                                        gsize         size);
+gsize                 g_io_channel_get_buffer_size      (GIOChannel   *channel);
+GIOCondition          g_io_channel_get_buffer_condition (GIOChannel   *channel);
+GIOStatus             g_io_channel_set_flags            (GIOChannel   *channel,
+                                                        GIOFlags      flags,
+                                                        GError      **error);
+GIOFlags              g_io_channel_get_flags            (GIOChannel   *channel);
+void                  g_io_channel_set_line_term        (GIOChannel   *channel,
+                                                        const gchar  *line_term);
+G_CONST_RETURN gchar* g_io_channel_get_line_term        (GIOChannel   *channel);
+GIOStatus             g_io_channel_set_encoding         (GIOChannel   *channel,
+                                                        const gchar  *encoding,
+                                                        GError      **error);
+G_CONST_RETURN gchar* g_io_channel_get_encoding         (GIOChannel   *channel);
+
+
+GIOStatus   g_io_channel_flush            (GIOChannel   *channel,
+                                          GError      **error);
+GIOStatus   g_io_channel_read_line        (GIOChannel   *channel,
+                                          gchar       **str_return,
+                                          gsize        *length,
+                                          gsize        *terminator_pos,
+                                          GError      **error);
+GIOStatus   g_io_channel_read_line_string (GIOChannel   *channel,
+                                          GString      *buffer,
+                                          gsize        *terminator_pos,
+                                          GError      **error);
+GIOStatus   g_io_channel_read_to_end      (GIOChannel   *channel,
+                                          gchar       **str_return,
+                                          gsize        *length,
+                                          GError      **error);
+GIOStatus   g_io_channel_read_chars       (GIOChannel   *channel,
+                                          gchar        *buf,
+                                          gsize         count,
+                                          gsize        *bytes_read,
+                                          GError      **error);
+GIOStatus   g_io_channel_write_chars      (GIOChannel   *channel,
+                                          const gchar  *buf,
+                                          gssize        count,
+                                          gsize        *bytes_written,
+                                          GError      **error);
+GIOStatus   g_io_channel_seek_position    (GIOChannel   *channel,
+                                          glong         offset,
+                                          GSeekType     type,
+                                          GError      **error);
+GIOChannel* g_io_channel_new_file         (const gchar  *filename,
+                                          GIOFileMode   mode,
+                                          GError      **error);
+
+/* Error handling */
+
+GQuark          g_channel_error_quark      (void);
+GIOChannelError g_channel_error_from_errno (gint en);
 
 /* On Unix, IO channels created with this function for any file
  * descriptor or socket.
@@ -178,7 +334,7 @@ GIOChannel *g_io_channel_win32_new_messages (guint hwnd);
  * the file descriptor should be done by this internal GLib
  * thread. Your code should call only g_io_channel_read().
  */
-GIOChannel* g_io_channel_win32_new_fd (int         fd);
+GIOChannel* g_io_channel_win32_new_fd (gint         fd);
 
 /* Get the C runtime file descriptor of a channel. */
 gint        g_io_channel_win32_get_fd (GIOChannel *channel);
index ca98e0c860f4b27aca3eef05706068036d88d055..0bafcbbee16ccabb19481e044c04e15eb8028cd7 100644 (file)
 
 #include "glib.h"
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
+#include <string.h>
+#include <fcntl.h>
 
 /*
  * Unix IO Channels
@@ -59,21 +63,29 @@ struct _GIOUnixWatch
 };
 
 
-static GIOError g_io_unix_read         (GIOChannel   *channel,
-                                       gchar        *buf,
-                                       guint         count,
-                                       guint        *bytes_written);
-static GIOError g_io_unix_write        (GIOChannel   *channel,
-                                       gchar        *buf,
-                                       guint         count,
-                                       guint        *bytes_written);
-static GIOError g_io_unix_seek         (GIOChannel   *channel,
-                                       gint          offset,
-                                       GSeekType     type);
-static void     g_io_unix_close        (GIOChannel   *channel);
-static void     g_io_unix_free         (GIOChannel   *channel);
-static GSource *g_io_unix_create_watch (GIOChannel   *channel,
-                                       GIOCondition  condition);
+static GIOStatus       g_io_unix_read          (GIOChannel   *channel,
+                                                gchar        *buf,
+                                                gsize         count,
+                                                gsize        *bytes_read,
+                                                GError      **err);
+static GIOStatus       g_io_unix_write         (GIOChannel   *channel,
+                                                const gchar  *buf,
+                                                gsize         count,
+                                                gsize        *bytes_written,
+                                                GError      **err);
+static GIOStatus       g_io_unix_seek          (GIOChannel   *channel,
+                                                glong         offset,
+                                                GSeekType     type,
+                                                GError      **err);
+static GIOStatus       g_io_unix_close         (GIOChannel   *channel,
+                                                GError      **err);
+static void            g_io_unix_free          (GIOChannel   *channel);
+static GSource*                g_io_unix_create_watch  (GIOChannel   *channel,
+                                                GIOCondition  condition);
+static GIOStatus       g_io_unix_set_flags     (GIOChannel   *channel,
+                                                        GIOFlags      flags,
+                                                GError      **err);
+static GIOFlags        g_io_unix_get_flags     (GIOChannel   *channel);
 
 static gboolean g_io_unix_prepare  (GSource     *source,
                                    gint        *timeout);
@@ -97,14 +109,26 @@ GIOFuncs unix_channel_funcs = {
   g_io_unix_close,
   g_io_unix_create_watch,
   g_io_unix_free,
+  g_io_unix_set_flags,
+  g_io_unix_get_flags,
 };
 
 static gboolean 
 g_io_unix_prepare (GSource  *source,
                   gint     *timeout)
 {
+  GIOUnixWatch *watch = (GIOUnixWatch *)source;
+
   *timeout = -1;
-  return FALSE;
+
+  /* Only return TRUE if we're sure to match all conditions, otherwise
+   * we need to check.
+   */
+
+  watch->condition = g_io_channel_get_buffer_condition (watch->channel);
+
+  return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition;
+
 }
 
 static gboolean 
@@ -112,6 +136,8 @@ g_io_unix_check (GSource  *source)
 {
   GIOUnixWatch *watch = (GIOUnixWatch *)source;
 
+  watch->condition &= g_io_channel_get_buffer_condition (watch->channel);
+
   return (watch->pollfd.revents & watch->condition);
 }
 
@@ -144,74 +170,91 @@ g_io_unix_destroy (GSource *source)
   g_io_channel_unref (watch->channel);
 }
 
-static GIOError 
+static GIOStatus
 g_io_unix_read (GIOChannel *channel, 
-               gchar     *buf, 
-               guint      count,
-               guint     *bytes_read)
+               gchar      *buf, 
+               gsize       count,
+               gsize      *bytes_read,
+               GError    **err)
 {
   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
-  gint result;
+  gssize result;
 
+ retry:
   result = read (unix_channel->fd, buf, count);
 
   if (result < 0)
     {
       *bytes_read = 0;
+
       switch (errno)
-       {
-       case EINVAL:
-         return G_IO_ERROR_INVAL;
-       case EAGAIN:
-       case EINTR:
-         return G_IO_ERROR_AGAIN;
-       default:
-         return G_IO_ERROR_UNKNOWN;
-       }
-    }
-  else
-    {
-      *bytes_read = result;
-      return G_IO_ERROR_NONE;
+        {
+#ifdef EINTR
+          case EINTR:
+            goto retry;
+#endif
+#ifdef EAGAIN
+          case EAGAIN:
+            return G_IO_STATUS_AGAIN;
+#endif
+          default:
+            g_set_error (err, G_IO_CHANNEL_ERROR,
+                         g_channel_error_from_errno (errno),
+                         strerror (errno));
+            return G_IO_STATUS_ERROR;
+        }
     }
+
+  *bytes_read = result;
+
+  return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
 }
-                      
-static GIOError 
-g_io_unix_write(GIOChannel *channel, 
-               gchar     *buf, 
-               guint      count,
-               guint     *bytes_written)
+
+static GIOStatus
+g_io_unix_write (GIOChannel  *channel, 
+                const gchar *buf, 
+                gsize       count,
+                gsize      *bytes_written,
+                GError    **err)
 {
   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
-  gint result;
+  gssize result;
 
+ retry:
   result = write (unix_channel->fd, buf, count);
 
   if (result < 0)
     {
       *bytes_written = 0;
+
       switch (errno)
-       {
-       case EINVAL:
-         return G_IO_ERROR_INVAL;
-       case EAGAIN:
-       case EINTR:
-         return G_IO_ERROR_AGAIN;
-       default:
-         return G_IO_ERROR_UNKNOWN;
-       }
-    }
-  else
-    {
-      *bytes_written = result;
-      return G_IO_ERROR_NONE;
+        {
+#ifdef EINTR
+          case EINTR:
+            goto retry;
+#endif
+#ifdef EAGAIN
+          case EAGAIN:
+            return G_IO_STATUS_AGAIN;
+#endif
+          default:
+            g_set_error (err, G_IO_CHANNEL_ERROR,
+                         g_channel_error_from_errno (errno),
+                         strerror (errno));
+            return G_IO_STATUS_ERROR;
+        }
     }
+
+  *bytes_written = result;
+
+  return G_IO_STATUS_NORMAL;
 }
 
-static GIOError 
+static GIOStatus
 g_io_unix_seek (GIOChannel *channel,
-               gint      offset, 
-               GSeekType type)
+               glong       offset, 
+               GSeekType   type,
+                GError    **err)
 {
   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
   int whence;
@@ -229,33 +272,39 @@ g_io_unix_seek (GIOChannel *channel,
       whence = SEEK_END;
       break;
     default:
-      g_warning ("g_io_unix_seek: unknown seek type");
-      return G_IO_ERROR_UNKNOWN;
+      whence = -1; /* Shut the compiler up */
+      g_assert_not_reached ();
     }
 
   result = lseek (unix_channel->fd, offset, whence);
 
   if (result < 0)
     {
-      switch (errno)
-       {
-       case EINVAL:
-         return G_IO_ERROR_INVAL;
-       default:
-         return G_IO_ERROR_UNKNOWN;
-       }
+      g_set_error (err, G_IO_CHANNEL_ERROR,
+                  g_channel_error_from_errno (errno),
+                  strerror (errno));
+      return G_IO_STATUS_ERROR;
     }
-  else
-    return G_IO_ERROR_NONE;
+
+  return G_IO_STATUS_NORMAL;
 }
 
 
-static void 
-g_io_unix_close (GIOChannel *channel)
+static GIOStatus
+g_io_unix_close (GIOChannel *channel,
+                GError    **err)
 {
   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
 
-  close (unix_channel->fd);
+  if (close (unix_channel->fd) < 0)
+    {
+      g_set_error (err, G_IO_CHANNEL_ERROR,
+                  g_channel_error_from_errno (errno),
+                  strerror (errno));
+      return G_IO_STATUS_ERROR;
+    }
+
+  return G_IO_STATUS_NORMAL;
 }
 
 static void 
@@ -291,6 +340,154 @@ g_io_unix_create_watch (GIOChannel   *channel,
   return source;
 }
 
+static const GIOFlags g_io_unix_fcntl_flags[] = {
+  G_IO_FLAG_APPEND,
+  G_IO_FLAG_NONBLOCK,
+};
+static const glong g_io_unix_fcntl_posix_flags[] = {
+  O_APPEND,
+#ifdef O_NONBLOCK
+  O_NONBLOCK,
+#else
+  O_NDELAY,
+#endif
+};
+#define G_IO_UNIX_NUM_FCNTL_FLAGS G_N_ELEMENTS (g_io_unix_fcntl_flags)
+
+static const GIOFlags g_io_unix_fcntl_flags_read_only[] = {
+  G_IO_FLAG_IS_READABLE,
+  G_IO_FLAG_IS_WRITEABLE,
+};
+static const glong g_io_unix_fcntl_posix_flags_read_only[] = {
+  O_RDONLY | O_RDWR,
+  O_WRONLY | O_RDWR,
+};
+/* Only need to map posix_flags -> flags for read only, not the
+ * other way around, so this works.
+ */
+#define G_IO_UNIX_NUM_FCNTL_FLAGS_READ_ONLY G_N_ELEMENTS (g_io_unix_fcntl_flags_read_only)
+
+static GIOStatus
+g_io_unix_set_flags (GIOChannel *channel,
+                     GIOFlags    flags,
+                     GError    **err)
+{
+  glong fcntl_flags;
+  gint loop;
+  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
+
+  fcntl_flags = 0;
+
+  for (loop = 0; loop < G_IO_UNIX_NUM_FCNTL_FLAGS; loop++)
+    if (flags & g_io_unix_fcntl_flags[loop])
+      fcntl_flags |= g_io_unix_fcntl_posix_flags[loop];
+
+  if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
+    {
+      g_set_error (err, G_IO_CHANNEL_ERROR,
+                  g_channel_error_from_errno (errno),
+                  g_strerror (errno));
+      return G_IO_STATUS_ERROR;
+    }
+
+  return G_IO_STATUS_NORMAL;
+}
+
+static GIOFlags
+g_io_unix_get_flags (GIOChannel *channel)
+{
+  GIOFlags flags = 0;
+  glong fcntl_flags;
+  gint loop;
+  GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
+  struct stat buffer;
+
+  fcntl_flags = fcntl (unix_channel->fd, F_GETFL);
+  if (fcntl_flags == -1)
+    {
+      g_warning (G_STRLOC "Error while getting flags for FD: %s (%d)\n",
+                g_strerror (errno), errno);
+      return 0;
+    }
+  if (!channel->seekable_cached)
+    {
+      channel->seekable_cached = TRUE;
+
+      /* I'm not sure if fstat on a non-file (e.g., socket) works
+       * it should be safe to sat if it fails, the fd isn't seekable.
+       */
+      if (fstat (unix_channel->fd, &buffer) == -1 ||
+         !S_ISREG (buffer.st_mode))
+       channel->is_seekable = FALSE;
+      else
+       channel->is_seekable = TRUE;
+    }
+
+  for (loop = 0; loop < G_IO_UNIX_NUM_FCNTL_FLAGS; loop++)
+    if (fcntl_flags & g_io_unix_fcntl_posix_flags[loop])
+      flags |= g_io_unix_fcntl_flags[loop];
+
+  for (loop = 0; loop < G_IO_UNIX_NUM_FCNTL_FLAGS_READ_ONLY; loop++)
+    if (fcntl_flags & g_io_unix_fcntl_posix_flags_read_only[loop])
+      flags |= g_io_unix_fcntl_flags_read_only[loop];
+
+  if (channel->is_seekable)
+    flags |= G_IO_FLAG_IS_SEEKABLE;
+
+  return flags;
+}
+
+GIOChannel *
+g_io_channel_new_file (const gchar *filename,
+                       GIOFileMode  mode,
+                       GError     **error)
+{
+  FILE *f;
+  int fid;
+  gchar *mode_name;
+  GIOChannel *channel;
+
+  switch (mode)
+    {
+      case G_IO_FILE_MODE_READ:
+        mode_name = "r";
+        break;
+      case G_IO_FILE_MODE_WRITE:
+        mode_name = "w";
+        break;
+      case G_IO_FILE_MODE_APPEND:
+        mode_name = "a";
+        break;
+      case G_IO_FILE_MODE_READ_WRITE:
+        mode_name = "r+";
+        break;
+      case G_IO_FILE_MODE_READ_WRITE_TRUNCATE:
+        mode_name = "w+";
+        break;
+      case G_IO_FILE_MODE_READ_WRITE_APPEND:
+        mode_name = "a+";
+        break;
+      default:
+        g_warning ("Invalid GIOFileMode %i.\n", mode);
+        return NULL;
+    }
+
+  f = fopen (filename, mode_name);
+  if (!f)
+    {
+      g_set_error (error, G_FILE_ERROR,
+                   g_file_error_from_errno (errno),
+                   strerror (errno));
+      return (GIOChannel *)NULL;
+    }
+    
+  fid = fileno (f);
+
+  channel = g_io_channel_unix_new (fid);
+  channel->close_on_unref = TRUE;
+  return channel;
+}
+
 GIOChannel *
 g_io_channel_unix_new (gint fd)
 {
index 30507fd5c0189129d9ab30e437b0c33f281220bb..d9e63320e710d8da75b76e863f8c2c9cc291c4c5 100644 (file)
@@ -43,6 +43,8 @@
 #include <errno.h>
 #include <sys/stat.h>
 
+#include "glibintl.h"
+
 typedef struct _GIOWin32Channel GIOWin32Channel;
 typedef struct _GIOWin32Watch GIOWin32Watch;
 
@@ -292,11 +294,12 @@ create_thread (GIOWin32Channel     *channel,
   WaitForSingleObject (channel->space_avail_event, INFINITE);
 }
 
-static int
+static GIOStatus
 buffer_read (GIOWin32Channel *channel,
             guchar          *dest,
-            guint            count,
-            GIOError        *error)
+            gsize            count,
+            gsize           *bytes_read,
+            GError         **err)
 {
   guint nbytes;
   guint left = count;
@@ -318,7 +321,8 @@ buffer_read (GIOWin32Channel *channel,
       if (channel->wrp == channel->rdp && !channel->running)
        {
          UNLOCK (channel->mutex);
-         return 0;
+          *bytes_read = 0;
+         return G_IO_STATUS_EOF; /* Is this correct? FIXME */
        }
     }
   
@@ -354,8 +358,8 @@ buffer_read (GIOWin32Channel *channel,
   /* We have no way to indicate any errors form the actual
    * read() or recv() call in the reader thread. Should we have?
    */
-  *error = G_IO_ERROR_NONE;
-  return count - left;
+  *bytes_read = count - left;
+  return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
 }
 
 static unsigned __stdcall
@@ -514,7 +518,9 @@ g_io_win32_prepare (GSource *source,
                 channel->thread_id);
     }
 
-  return FALSE;
+  watch->condition = g_io_channel_get_buffer_condition (watch->channel);
+
+  return (watch->pollfd.revents & (G_IO_IN | G_IO_OUT)) == watch->condition;
 }
 
 static gboolean
@@ -549,6 +555,8 @@ g_io_win32_check (GSource *source)
        g_print ("g_io_win32_check: thread %#x, there.\n",
                 channel->thread_id);
     }
+
+  watch->condition &= g_io_channel_get_buffer_condition (watch->channel);
   
   return (watch->pollfd.revents & watch->condition);
 }
@@ -633,56 +641,76 @@ g_io_win32_create_watch (GIOChannel    *channel,
   return source;
 }
 
-static GIOError
+static GIOStatus
 g_io_win32_msg_read (GIOChannel *channel,
                     gchar      *buf,
-                    guint       count,
-                    guint      *bytes_read)
+                    gsize       count,
+                    gsize      *bytes_read,
+                    GError    **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   MSG msg;               /* In case of alignment problems */
   
   if (count < sizeof (MSG))
-    return G_IO_ERROR_INVAL;
+    {
+      g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
+        _("Incorrect message size")); /* Correct error message? FIXME */
+      return G_IO_STATUS_ERROR;
+    }
   
   if (win32_channel->debug)
     g_print ("g_io_win32_msg_read: for %#x\n",
             win32_channel->hwnd);
   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
-    return G_IO_ERROR_AGAIN;
+    return G_IO_STATUS_AGAIN;
   
   memmove (buf, &msg, sizeof (MSG));
   *bytes_read = sizeof (MSG);
-  return G_IO_ERROR_NONE;
+
+  return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
 }
 
-static GIOError
-g_io_win32_msg_write (GIOChannel *channel,
-                     gchar      *buf,
-                     guint       count,
-                     guint      *bytes_written)
+static GIOStatus
+g_io_win32_msg_write (GIOChannel  *channel,
+                     const gchar *buf,
+                     gsize        count,
+                     gsize       *bytes_written,
+                     GError     **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   MSG msg;
   
   if (count != sizeof (MSG))
-    return G_IO_ERROR_INVAL;
+    {
+      g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
+        _("Incorrect message size")); /* Correct error message? FIXME */
+      return G_IO_STATUS_ERROR;
+    }
   
   /* In case of alignment problems */
   memmove (&msg, buf, sizeof (MSG));
   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
-    return G_IO_ERROR_UNKNOWN;
-  
+    {
+      g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED
+        _("Unknown error")); /* Correct error message? FIXME */
+      return G_IO_STATUS_ERROR;
+    }
+
   *bytes_written = sizeof (MSG);
-  return G_IO_ERROR_NONE;
+
+  return G_IO_STATUS_NORMAL;
 }
 
-static GIOError
+static GIOStatus
 g_io_win32_no_seek (GIOChannel *channel,
                    gint        offset,
-                   GSeekType   type)
+                   GSeekType   type,
+                   GError     **err)
 {
-  return G_IO_ERROR_UNKNOWN;
+  g_set_error(error, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_SPIPE,
+    _("Seeking not allowed on this type of channel"));
+
+  return G_IO_STATUS_ERROR;
 }
 
 static void
@@ -737,15 +765,15 @@ g_io_win32_msg_create_watch (GIOChannel    *channel,
   return source;
 }
 
-static GIOError
+static GIOStatus
 g_io_win32_fd_read (GIOChannel *channel,
                    gchar      *buf,
-                   guint       count,
-                   guint      *bytes_read)
+                   gsize       count,
+                   gsize      *bytes_read,
+                   GError    **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   gint result;
-  GIOError error;
   
   if (win32_channel->debug)
     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
@@ -753,17 +781,7 @@ g_io_win32_fd_read (GIOChannel *channel,
   
   if (win32_channel->thread_id)
     {
-      result = buffer_read (win32_channel, buf, count, &error);
-      if (result < 0)
-       {
-         *bytes_read = 0;
-         return error;
-       }
-      else
-       {
-         *bytes_read = result;
-         return G_IO_ERROR_NONE;
-       }
+      return buffer_read (win32_channel, buf, count, bytes_read, err);
     }
 
   result = read (win32_channel->fd, buf, count);
@@ -771,23 +789,32 @@ g_io_win32_fd_read (GIOChannel *channel,
   if (result < 0)
     {
       *bytes_read = 0;
-      if (errno == EINVAL)
-       return G_IO_ERROR_INVAL;
-      else
-       return G_IO_ERROR_UNKNOWN;
-    }
-  else
-    {
-      *bytes_read = result;
-      return G_IO_ERROR_NONE;
+
+      switch(errno)
+        {
+#ifdef EAGAIN
+          case EAGAIN:
+            return G_IO_STATUS_AGAIN;
+#endif
+          default:
+            g_set_error (err, G_IO_CHANNEL_ERROR,
+                         g_channel_error_from_errno (errno),
+                         strerror (errno));
+            return G_IO_STATUS_ERROR;
+        }
     }
+
+  *bytes_read = result;
+
+  return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
 }
 
-static GIOError
-g_io_win32_fd_write (GIOChannel *channel,
-                    gchar      *buf,
-                    guint       count,
-                    guint      *bytes_written)
+static GIOStatus
+g_io_win32_fd_write (GIOChannel  *channel,
+                    const gchar *buf,
+                    gsize        count,
+                    gsize       *bytes_written,
+                    GError     **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   gint result;
@@ -796,31 +823,35 @@ g_io_win32_fd_write (GIOChannel *channel,
   if (win32_channel->debug)
     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
             win32_channel->fd, count, result);
-  
+
   if (result < 0)
     {
       *bytes_written = 0;
-      switch (errno)
-       {
-       case EINVAL:
-         return G_IO_ERROR_INVAL;
-       case EAGAIN:
-         return G_IO_ERROR_AGAIN;
-       default:
-         return G_IO_ERROR_UNKNOWN;
-       }
-    }
-  else
-    {
-      *bytes_written = result;
-      return G_IO_ERROR_NONE;
+
+      switch(errno)
+        {
+#ifdef EAGAIN
+          case EAGAIN:
+            return G_IO_STATUS_AGAIN;
+#endif
+          default:
+            g_set_error (err, G_IO_CHANNEL_ERROR,
+                         g_channel_error_from_errno (errno),
+                         strerror (errno));
+            return G_IO_STATUS_ERROR;
+        }
     }
+
+  *bytes_written = result;
+
+  return G_IO_STATUS_NORMAL;
 }
 
-static GIOError
+static GIOStatus
 g_io_win32_fd_seek (GIOChannel *channel,
                    gint        offset,
-                   GSeekType   type)
+                   GSeekType   type,
+                   GError    **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   int whence;
@@ -838,24 +869,21 @@ g_io_win32_fd_seek (GIOChannel *channel,
       whence = SEEK_END;
       break;
     default:
-      g_warning (G_STRLOC ": Unknown seek type %d", (int) type);
-      return G_IO_ERROR_UNKNOWN;
+      whence = -1; /* Keep the compiler quiet */
+      g_assert_not_reached();
     }
   
   result = lseek (win32_channel->fd, offset, whence);
   
   if (result < 0)
     {
-      switch (errno)
-       {
-       case EINVAL:
-         return G_IO_ERROR_INVAL;
-       default:
-         return G_IO_ERROR_UNKNOWN;
-       }
+      g_set_error (err, G_IO_CHANNEL_ERROR,
+                  g_channel_error_from_errno (errno),
+                  strerror (errno));
+      return G_IO_STATUS_ERROR;
     }
-  else
-    return G_IO_ERROR_NONE;
+
+  return G_IO_STATUS_NORMAL;
 }
 
 static void
@@ -897,15 +925,16 @@ g_io_win32_fd_create_watch (GIOChannel    *channel,
   return g_io_win32_create_watch (channel, condition, read_thread);
 }
 
-static GIOError
+static GIOStatus
 g_io_win32_sock_read (GIOChannel *channel,
                      gchar      *buf,
-                     guint       count,
-                     guint      *bytes_read)
+                     gsize       count,
+                     gsize      *bytes_read,
+                     GError    **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   gint result;
-  GIOError error;
+  GIOChannelError error;
 
   if (win32_channel->debug)
     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
@@ -919,32 +948,42 @@ g_io_win32_sock_read (GIOChannel *channel,
   if (result == SOCKET_ERROR)
     {
       *bytes_read = 0;
+
       switch (WSAGetLastError ())
        {
        case WSAEINVAL:
-         return G_IO_ERROR_INVAL;
+          error = G_IO_CHANNEL_ERROR_INVAL;
+          break;
        case WSAEWOULDBLOCK:
+          return G_IO_STATUS_AGAIN;
        case WSAEINTR:
-         return G_IO_ERROR_AGAIN;
+          return G_IO_STATUS_INTR;
        default:
-         return G_IO_ERROR_UNKNOWN;
+         error = G_IO_CHANNEL_ERROR_FAILED;
+          break;
        }
+      g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
+      return G_IO_STATUS_ERROR;
+      /* FIXME get all errors, better error messages */
     }
   else
     {
       *bytes_read = result;
-      return G_IO_ERROR_NONE;
+
+      return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
     }
 }
 
-static GIOError
-g_io_win32_sock_write (GIOChannel *channel,
-                      gchar      *buf,
-                      guint       count,
-                      guint      *bytes_written)
+static GIOStatus
+g_io_win32_sock_write (GIOChannel  *channel,
+                      const gchar *buf,
+                      gsize        count,
+                      gsize       *bytes_written,
+                      GError     **err)
 {
   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
   gint result;
+  GIOChannelError error;
   
   if (win32_channel->debug)
     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
@@ -958,21 +997,29 @@ g_io_win32_sock_write (GIOChannel *channel,
   if (result == SOCKET_ERROR)
     {
       *bytes_written = 0;
+
       switch (WSAGetLastError ())
        {
        case WSAEINVAL:
-         return G_IO_ERROR_INVAL;
+         error = G_IO_CHANNEL_ERROR_INVAL;
+          break;
        case WSAEWOULDBLOCK:
+          return G_IO_STATUS_AGAIN;
        case WSAEINTR:
-         return G_IO_ERROR_AGAIN;
+         return G_IO_STATUS_INTR;
        default:
-         return G_IO_ERROR_UNKNOWN;
+         error = G_IO_CHANNEL_ERROR_FAILED;
+          break;
        }
+      g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
+      return G_IO_STATUS_ERROR;
+      /* FIXME get all errors, better error messages */
     }
   else
     {
       *bytes_written = result;
-      return G_IO_ERROR_NONE;
+
+      return G_IO_STATUS_NORMAL;
     }
 }
 
@@ -1011,13 +1058,45 @@ g_io_win32_sock_create_watch (GIOChannel    *channel,
   return g_io_win32_create_watch (channel, condition, select_thread);
 }
 
+/* Some functions prototypes so win32 will (hopefully) still compile FIXME */
+
+GIOChannel *
+g_io_channel_new_file (const gchar  *filename,
+                       GIOFileMode   mode,
+                       GError      **error)
+{
+  g_warning("Function unimplemented: %s", G_GNUC_FUNCTION);
+
+  return NULL;
+}
+
+GIOStatus
+g_io_win32_set_flags (GIOChannel     *channel,
+                      GIOFlags        flags,
+                      GError        **err)
+{
+  g_message("Function %s unimplemented.\n", G_GNUC_FUNCTION);
+
+  return G_IO_STATUS_NORMAL; /* Can't return error, haven't set err */
+}
+
+GIOFlags
+g_io_win32_get_flags (GIOChannel     *channel)
+{
+  g_message("Function %s unimplemented.\n", G_GNUC_FUNCTION);
+
+  return 0;
+}
+
 static GIOFuncs win32_channel_msg_funcs = {
   g_io_win32_msg_read,
   g_io_win32_msg_write,
   g_io_win32_no_seek,
   g_io_win32_msg_close,
   g_io_win32_msg_create_watch,
-  g_io_win32_free
+  g_io_win32_free,
+  g_io_win32_set_flags,
+  g_io_win32_get_flags,
 };
 
 static GIOFuncs win32_channel_fd_funcs = {
@@ -1026,7 +1105,9 @@ static GIOFuncs win32_channel_fd_funcs = {
   g_io_win32_fd_seek,
   g_io_win32_fd_close,
   g_io_win32_fd_create_watch,
-  g_io_win32_free
+  g_io_win32_free,
+  g_io_win32_set_flags,
+  g_io_win32_get_flags,
 };
 
 static GIOFuncs win32_channel_sock_funcs = {
@@ -1035,7 +1116,9 @@ static GIOFuncs win32_channel_sock_funcs = {
   g_io_win32_no_seek,
   g_io_win32_sock_close,
   g_io_win32_sock_create_watch,
-  g_io_win32_free
+  g_io_win32_free,
+  g_io_win32_set_flags,
+  g_io_win32_get_flags,
 };
 
 GIOChannel *
index 89f4467fbca13cb55a15400ed1419dad3a6b7aa7..51448f3cabcbb36577cfc21e747741ca9f84075f 100644 (file)
@@ -51,6 +51,8 @@ EXPORTS
        g_cache_new
        g_cache_remove
        g_cache_value_foreach
+       g_channel_error_quark
+       g_channel_error_from_errno
        g_clear_error
        g_completion_add_items
        g_completion_clear_items
@@ -184,10 +186,26 @@ EXPORTS
        g_io_add_watch
        g_io_add_watch_full
        g_io_channel_close
+       g_io_channel_flush
+       g_io_channel_get_buffer_condition
+       g_io_channel_get_buffer_size
+       g_io_channel_get_encoding
+       g_io_channel_get_flags
+       g_io_channel_get_line_term
        g_io_channel_init
+       g_io_channel_new_file
        g_io_channel_read
+       g_io_channel_read_chars
+       g_io_channel_read_line
+       g_io_channel_read_line_string
+       g_io_channel_read_to_end
        g_io_channel_ref
        g_io_channel_seek
+       g_io_channel_seek_position
+       g_io_channel_set_buffer_size
+       g_io_channel_set_encoding
+       g_io_channel_set_flags
+       g_io_channel_set_line_term
        g_io_channel_unix_get_fd
        g_io_channel_unix_new
        g_io_channel_unref
@@ -200,6 +218,7 @@ EXPORTS
        g_io_channel_win32_poll
        g_io_channel_win32_set_debug
        g_io_channel_write
+       g_io_channel_write_chars
        g_io_create_watch
        g_list_alloc
        g_list_append
index df64869a1033c7be50778e46f8ffbcc57c5c732b..bc450e4a86a4a748f682e5c0a971fb73ef4ab8cf 100644 (file)
@@ -58,7 +58,7 @@ struct _GRealString
 {
   gchar *str;
   gsize len;    
-  gsize alloc;  
+  gsize allocated_len;  
 };
 
 G_LOCK_DEFINE_STATIC (string_mem_chunk);
@@ -212,10 +212,10 @@ static void
 g_string_maybe_expand (GRealString* string,
                       gsize        len) 
 {
-  if (string->len + len >= string->alloc)
+  if (string->len + len >= string->allocated_len)
     {
-      string->alloc = nearest_power (1, string->len + len + 1);
-      string->str = g_realloc (string->str, string->alloc);
+      string->allocated_len = nearest_power (1, string->len + len + 1);
+      string->str = g_realloc (string->str, string->allocated_len);
     }
 }
 
@@ -233,7 +233,7 @@ g_string_sized_new (gsize dfl_size)
   string = g_chunk_new (GRealString, string_mem_chunk);
   G_UNLOCK (string_mem_chunk);
 
-  string->alloc = 0;
+  string->allocated_len = 0;
   string->len   = 0;
   string->str   = NULL;
 
@@ -368,6 +368,36 @@ g_string_truncate (GString *fstring,
   return fstring;
 }
 
+/**
+ * g_string_set_size:
+ * @fstring: a #GString
+ * @len: the new length
+ * 
+ * Sets the length of a #GString. If the length is less than
+ * the current length, the string will be truncated. If the
+ * length is greater than the current length, the contents
+ * of the newly added area are undefined. (However, as
+ * always, string->str[string->len] will be a nul byte.) 
+ * 
+ * Return value: @fstring
+ **/
+GString*
+g_string_set_size (GString *fstring,
+                  gsize    len)    
+{
+  GRealString *string = (GRealString *) fstring;
+
+  g_return_val_if_fail (string != NULL, NULL);
+
+  if (len >= string->allocated_len)
+    g_string_maybe_expand (string, len - fstring->len);
+  
+  string->len = len;
+  string->str[len] = 0;
+
+  return fstring;
+}
+
 GString*
 g_string_insert_len (GString     *fstring,
                     gssize       pos,    
index ed01fa95e9da230756884354781b21a522e2a4e3..4337f3c7e7f85ea3c01d57aeaeb0ab63a76ea7c4 100644 (file)
@@ -37,7 +37,8 @@ typedef struct _GStringChunk  GStringChunk;
 struct _GString
 {
   gchar  *str;
-  gssize len;    
+  gsize len;    
+  gsize allocated_len;
 };
 
 /* String Chunks
@@ -65,6 +66,8 @@ GString*     g_string_assign            (GString       *string,
                                         const gchar     *rval);
 GString*     g_string_truncate          (GString        *string,
                                         gsize            len);    
+GString*     g_string_set_size          (GString         *string,
+                                        gsize            len);
 GString*     g_string_insert_len        (GString         *string,
                                          gssize           pos,   
                                          const gchar     *val,
index 49e277fc0da5b1b49811e1862a270bf7913e749a..d61329de73710a232fba9e5df54e2890b44dbbaf 100644 (file)
@@ -49,6 +49,7 @@ test_programs = \
        dirname-test    \
        gio-test        \
        hash-test       \
+       iochannel-test  \
        list-test       \
        mainloop-test   \
        module-test     \
@@ -86,6 +87,7 @@ date_test_LDADD = $(progs_LDADD)
 dirname_test_LDADD = $(progs_LDADD)
 gio_test_LDADD = $(progs_LDADD)
 hash_test_LDADD = $(progs_LDADD)
+iochannel_test_LDADD = $(progs_LDADD)
 list_test_LDADD = $(progs_LDADD)
 mainloop_test_LDADD = $(thread_LDADD)
 markup_test_LDADD = $(progs_LDADD)
diff --git a/tests/iochannel-test.c b/tests/iochannel-test.c
new file mode 100644 (file)
index 0000000..18ea01d
--- /dev/null
@@ -0,0 +1,138 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define BUFFER_SIZE 1024
+
+gint main (gint argc, gchar * argv[])
+{
+    GIOChannel *gio_r, *gio_w ;
+    GError *gerr = NULL;
+    GString *buffer;
+    gint rlength = 0, wlength = 0, length_out, line_term_len;
+    gboolean block;
+    const gchar encoding[] = "EUC-JP", line_term[] = G_IO_CHANNEL_UNIX_LINE_TERM;
+    GIOStatus status;
+    GIOFlags flags;
+
+    if (argc < 2)
+    {
+        g_print( "Usage: foo in-file\n" );
+        exit (1);
+    }
+
+    setbuf(stdout, NULL); /* For debugging */
+
+    gio_r = g_io_channel_new_file (argv[1], G_IO_FILE_MODE_READ, &gerr);
+    if(gerr) {
+      g_warning(gerr->message);
+      g_warning("Unable to open file %s", argv[1]);
+      g_free(gerr);
+      return 0;
+    }
+    gio_w = g_io_channel_new_file( "/var/tmp/fooOut.txt", G_IO_FILE_MODE_WRITE, &gerr);
+    if(gerr) {
+      g_warning(gerr->message);
+      g_free(gerr);
+      return 0;
+    }
+
+    g_io_channel_set_encoding (gio_r, encoding, &gerr);
+    if(gerr) {
+      g_warning(gerr->message);
+      g_free(gerr);
+      return 0;
+    }
+    
+    g_io_channel_set_buffer_size (gio_r, BUFFER_SIZE);
+
+    status = g_io_channel_set_flags (gio_r, G_IO_FLAG_NONBLOCK, &gerr);
+    if(status == G_IO_STATUS_ERROR) {
+      g_warning(gerr->message);
+      g_error_free(gerr);
+      gerr = NULL;
+    }
+    flags = g_io_channel_get_flags (gio_r);
+    block = ! (flags & G_IO_FLAG_NONBLOCK);
+    if (block)
+        g_print (" BLOCKING TRUE \n\n");
+    else
+        g_print (" BLOCKING FALSE \n\n");
+
+    line_term_len = strlen (line_term);
+    buffer = g_string_sized_new (BUFFER_SIZE);
+
+    while (TRUE)
+    {
+        do
+          status = g_io_channel_read_line_string (gio_r, buffer, NULL, &gerr);
+        while (status == G_IO_STATUS_AGAIN);
+        if (status != G_IO_STATUS_NORMAL)
+          break;
+
+        rlength += buffer->len;
+
+        do
+          status = g_io_channel_write_chars (gio_w, buffer->str, buffer->len,
+            &length_out, &gerr);
+        while (status == G_IO_STATUS_AGAIN);
+        if (status != G_IO_STATUS_NORMAL)
+          break;
+
+        wlength += length_out;
+
+        if (length_out < buffer->len)
+          g_warning ("Only wrote part of the line.");
+
+        do
+          status = g_io_channel_write_chars (gio_w, line_term,
+            line_term_len, &length_out, &gerr);
+        while (status == G_IO_STATUS_AGAIN);
+        if (status != G_IO_STATUS_NORMAL)
+          break;
+
+        if (length_out < line_term_len)
+          g_warning ("Only wrote part of the line term.");
+
+        g_print (": %s\n", buffer->str);
+        g_string_truncate (buffer, 0);
+    }
+
+    switch (status)
+      {
+        case G_IO_STATUS_EOF:
+          break;
+        case G_IO_STATUS_PARTIAL_CHARS:
+          g_warning ("Partial characters at the end of input.");
+          break;
+        case G_IO_STATUS_ERROR:
+          g_warning (gerr->message);
+          g_error_free (gerr);
+          gerr = NULL;
+          break;
+        default:
+          g_warning ("Abnormal exit from write loop.");
+          break;
+      }
+
+    do
+      status = g_io_channel_flush (gio_w, &gerr);
+    while (status == G_IO_STATUS_AGAIN);
+
+    if(status == G_IO_STATUS_ERROR) {
+      g_warning(gerr->message);
+      g_error_free(gerr);
+      gerr = NULL;
+    }
+
+    g_print ("read %d bytes, wrote %d bytes\n", rlength, wlength);
+
+    g_io_channel_unref(gio_r);
+    g_io_channel_unref(gio_w);
+    
+    return 0;
+}