+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,
+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,
+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,
+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,
+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,
+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,
+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,
+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,
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
<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
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>
g_string_insert_len
g_string_erase
g_string_truncate
+g_string_set_size
g_string_free
<SUBSECTION>
+<!-- ##### 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>
<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
#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>
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>
@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>
@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">
<!-- ##### 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 ##### -->
@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:
+
@str:
@len:
+@alloc:
<!-- ##### FUNCTION g_string_new ##### -->
<para>
@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.
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
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
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
* 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)
{
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 *
{
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;
+}
#include <glib/gmain.h>
#include <glib/gtypes.h>
+#include <glib/gstring.h>
G_BEGIN_DECLS
typedef struct _GIOChannel GIOChannel;
typedef struct _GIOFuncs GIOFuncs;
+
typedef enum
{
G_IO_ERROR_NONE,
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,
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,
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.
* 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);
#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
};
-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);
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
{
GIOUnixWatch *watch = (GIOUnixWatch *)source;
+ watch->condition &= g_io_channel_get_buffer_condition (watch->channel);
+
return (watch->pollfd.revents & watch->condition);
}
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;
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
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)
{
#include <errno.h>
#include <sys/stat.h>
+#include "glibintl.h"
+
typedef struct _GIOWin32Channel GIOWin32Channel;
typedef struct _GIOWin32Watch GIOWin32Watch;
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;
if (channel->wrp == channel->rdp && !channel->running)
{
UNLOCK (channel->mutex);
- return 0;
+ *bytes_read = 0;
+ return G_IO_STATUS_EOF; /* Is this correct? FIXME */
}
}
/* 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
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
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);
}
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
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",
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);
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;
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;
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
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",
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",
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;
}
}
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 = {
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 = {
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 *
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
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
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
{
gchar *str;
gsize len;
- gsize alloc;
+ gsize allocated_len;
};
G_LOCK_DEFINE_STATIC (string_mem_chunk);
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);
}
}
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;
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,
struct _GString
{
gchar *str;
- gssize len;
+ gsize len;
+ gsize allocated_len;
};
/* String Chunks
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,
dirname-test \
gio-test \
hash-test \
+ iochannel-test \
list-test \
mainloop-test \
module-test \
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)
--- /dev/null
+#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;
+}