Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- clients/Instantbird/giochannel.c | 2316 ++++++++++++++++++++++++++++++++
- clients/Instantbird/giounix.c | 598 ++++++++
- clients/Instantbird/giowin32.c | 2129 +++++++++++++++++++++++++++++
- clients/Instantbird/gstrcmp0.c | 22 +
- clients/Instantbird/linux/Makefile.in | 62 +
- clients/Instantbird/macosx/Makefile.in | 63 +
- clients/Instantbird/win32/Makefile.in | 63 +
- msn.c | 4 +
- 8 files changed, 5257 insertions(+), 0 deletions(-)
- create mode 100755 clients/Instantbird/giochannel.c
- create mode 100755 clients/Instantbird/giounix.c
- create mode 100755 clients/Instantbird/giowin32.c
- create mode 100755 clients/Instantbird/gstrcmp0.c
- create mode 100755 clients/Instantbird/linux/Makefile.in
- create mode 100755 clients/Instantbird/macosx/Makefile.in
- create mode 100755 clients/Instantbird/win32/Makefile.in
- diff --git a/clients/Instantbird/giochannel.c b/clients/Instantbird/giochannel.c
- new file mode 100755
- index 0000000..b067736
- --- /dev/null
- +++ b/clients/Instantbird/giochannel.c
- @@ -0,0 +1,2316 @@
- +/* GLIB - Library of useful routines for C programming
- + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- + *
- + * giochannel.c: IO Channel abstraction
- + * Copyright 1998 Owen Taylor
- + *
- + * This library is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2 of the License, or (at your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with this library; if not, write to the
- + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- + * Boston, MA 02111-1307, USA.
- + */
- +
- +/*
- + * Modified by the GLib Team and others 1997-2000. See the AUTHORS
- + * file for a list of people on the GLib Team. See the ChangeLog
- + * files for a list of changes. These files are distributed with
- + * GLib at ftp://ftp.gtk.org/pub/gtk/.
- + */
- +
- +/*
- + * MT safe
- + */
- +
- +#include "config.h"
- +
- +#include <string.h>
- +#include <errno.h>
- +#ifndef EILSEQ
- +# define EILSEQ 42
- +#endif
- +
- +#ifdef HAVE_UNISTD_H
- +#include <unistd.h>
- +#endif
- +
- +#undef G_DISABLE_DEPRECATED
- +
- +#include "glib.h"
- +
- +#include "giochannel.h"
- +
- +#include "glibintl.h"
- +
- +#include "galias.h"
- +
- +#define G_IO_NICE_BUF_SIZE 1024
- +
- +/* This needs to be as wide as the largest character in any possible encoding */
- +#define MAX_CHAR_SIZE 10
- +
- +/* Some simplifying macros, which reduce the need to worry whether the
- + * buffers have been allocated. These also make USE_BUF () an lvalue,
- + * which is used in g_io_channel_read_to_end ().
- + */
- +#define USE_BUF(channel) ((channel)->encoding ? (channel)->encoded_read_buf \
- + : (channel)->read_buf)
- +#define BUF_LEN(string) ((string) ? (string)->len : 0)
- +
- +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);
- +static GIOStatus g_io_channel_read_line_backend (GIOChannel *channel,
- + gsize *length,
- + gsize *terminator_pos,
- + GError **error);
- +
- +void
- +g_io_channel_init (GIOChannel *channel)
- +{
- + channel->ref_count = 1;
- + channel->encoding = g_strdup ("UTF-8");
- + channel->line_term = NULL;
- + channel->line_term_len = 0;
- + channel->buf_size = G_IO_NICE_BUF_SIZE;
- + channel->read_cd = (GIConv) -1;
- + channel->write_cd = (GIConv) -1;
- + channel->read_buf = NULL; /* Lazy allocate buffers */
- + channel->encoded_read_buf = NULL;
- + channel->write_buf = NULL;
- + channel->partial_write_buf[0] = '\0';
- + channel->use_buffer = TRUE;
- + channel->do_encode = FALSE;
- + channel->close_on_unref = FALSE;
- +}
- +
- +GIOChannel *
- +g_io_channel_ref (GIOChannel *channel)
- +{
- + g_return_val_if_fail (channel != NULL, NULL);
- +
- + g_atomic_int_inc (&channel->ref_count);
- +
- + return channel;
- +}
- +
- +void
- +g_io_channel_unref (GIOChannel *channel)
- +{
- + gboolean is_zero;
- +
- + g_return_if_fail (channel != NULL);
- +
- + is_zero = g_atomic_int_dec_and_test (&channel->ref_count);
- +
- + if (G_UNLIKELY (is_zero))
- + {
- + if (channel->close_on_unref)
- + g_io_channel_shutdown (channel, TRUE, NULL);
- + else
- + g_io_channel_purge (channel);
- + g_free (channel->encoding);
- + if (channel->read_cd != (GIConv) -1)
- + g_iconv_close (channel->read_cd);
- + if (channel->write_cd != (GIConv) -1)
- + g_iconv_close (channel->write_cd);
- + g_free (channel->line_term);
- + if (channel->read_buf)
- + g_string_free (channel->read_buf, TRUE);
- + if (channel->write_buf)
- + g_string_free (channel->write_buf, TRUE);
- + if (channel->encoded_read_buf)
- + g_string_free (channel->encoded_read_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:
- + g_return_val_if_fail (err != NULL, G_IO_ERROR_UNKNOWN);
- +
- + 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.
- + *
- + * Return value: %G_IO_ERROR_NONE if the operation was successful.
- + *
- + * Deprecated:2.2: Use g_io_channel_read_chars() instead.
- + **/
- +GIOError
- +g_io_channel_read (GIOChannel *channel,
- + gchar *buf,
- + 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);
- +
- + if (count == 0)
- + {
- + if (bytes_read)
- + *bytes_read = 0;
- + return G_IO_ERROR_NONE;
- + }
- +
- + g_return_val_if_fail (buf != NULL, G_IO_ERROR_UNKNOWN);
- +
- + status = channel->funcs->io_read (channel, buf, count, bytes_read, &err);
- +
- + 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.
- + *
- + * Return value: %G_IO_ERROR_NONE if the operation was successful.
- + *
- + * Deprecated:2.2: Use g_io_channel_write_chars() instead.
- + **/
- +GIOError
- +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);
- +
- + 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().
- + *
- + * Return value: %G_IO_ERROR_NONE if the operation was successful.
- + *
- + * Deprecated:2.2: Use g_io_channel_seek_position() instead.
- + **/
- +GIOError
- +g_io_channel_seek (GIOChannel *channel,
- + gint64 offset,
- + GSeekType type)
- +{
- + GError *err = NULL;
- + GIOError error;
- + GIOStatus status;
- +
- + g_return_val_if_fail (channel != NULL, G_IO_ERROR_UNKNOWN);
- + g_return_val_if_fail (channel->is_seekable, G_IO_ERROR_UNKNOWN);
- +
- + 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: One of "r", "w", "a", "r+", "w+", "a+". These have
- + * the same meaning as in fopen()
- + * @error: A location to return an error of type %G_FILE_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().
- + *
- + * Deprecated:2.2: Use g_io_channel_shutdown() instead.
- + **/
- +void
- +g_io_channel_close (GIOChannel *channel)
- +{
- + GError *err = NULL;
- +
- + g_return_if_fail (channel != NULL);
- +
- + 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->is_readable = FALSE;
- + channel->is_writeable = FALSE;
- + channel->is_seekable = 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 if @flush is %TRUE. The channel will not be freed until the
- + * last reference is dropped using g_io_channel_unref().
- + *
- + * Return value: the status of the operation.
- + **/
- +GIOStatus
- +g_io_channel_shutdown (GIOChannel *channel,
- + gboolean flush,
- + GError **err)
- +{
- + GIOStatus status, result;
- + GError *tmperr = NULL;
- +
- + g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
- + g_return_val_if_fail (err == NULL || *err == NULL, G_IO_STATUS_ERROR);
- +
- + if (channel->write_buf && channel->write_buf->len > 0)
- + {
- + if (flush)
- + {
- + GIOFlags flags;
- +
- + /* Set the channel to blocking, to avoid a busy loop
- + */
- + flags = g_io_channel_get_flags (channel);
- + /* Ignore any errors here, they're irrelevant */
- + g_io_channel_set_flags (channel, flags & ~G_IO_FLAG_NONBLOCK, NULL);
- +
- + result = g_io_channel_flush (channel, &tmperr);
- + }
- + else
- + result = G_IO_STATUS_NORMAL;
- +
- + g_string_truncate(channel->write_buf, 0);
- + }
- + else
- + result = G_IO_STATUS_NORMAL;
- +
- + if (channel->partial_write_buf[0] != '\0')
- + {
- + if (flush)
- + g_warning ("Partial character at end of write buffer not flushed.\n");
- + channel->partial_write_buf[0] = '\0';
- + }
- +
- + status = channel->funcs->io_close (channel, err);
- +
- + channel->close_on_unref = FALSE; /* Because we already did */
- + channel->is_readable = FALSE;
- + channel->is_writeable = FALSE;
- + channel->is_seekable = FALSE;
- +
- + if (status != G_IO_STATUS_NORMAL)
- + {
- + g_clear_error (&tmperr);
- + return status;
- + }
- + else if (result != G_IO_STATUS_NORMAL)
- + {
- + g_propagate_error (err, tmperr);
- + return result;
- + }
- + else
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +/* This function is used for the final flush on close or unref */
- +static void
- +g_io_channel_purge (GIOChannel *channel)
- +{
- + GError *err = NULL;
- + GIOStatus status;
- +
- + g_return_if_fail (channel != NULL);
- +
- + if (channel->write_buf && 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);
- +
- + status = 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 */
- +
- + if (channel->read_buf)
- + g_string_truncate (channel->read_buf, 0);
- + if (channel->write_buf)
- + g_string_truncate (channel->write_buf, 0);
- + if (channel->encoding)
- + {
- + if (channel->encoded_read_buf)
- + g_string_truncate (channel->encoded_read_buf, 0);
- +
- + if (channel->partial_write_buf[0] != '\0')
- + {
- + g_warning ("Partial character at end of write buffer not flushed.\n");
- + channel->partial_write_buf[0] = '\0';
- + }
- + }
- +}
- +
- +GSource *
- +g_io_create_watch (GIOChannel *channel,
- + GIOCondition condition)
- +{
- + g_return_val_if_fail (channel != NULL, NULL);
- +
- + return channel->funcs->io_create_watch (channel, condition);
- +}
- +
- +guint
- +g_io_add_watch_full (GIOChannel *channel,
- + gint priority,
- + GIOCondition condition,
- + GIOFunc func,
- + gpointer user_data,
- + GDestroyNotify notify)
- +{
- + GSource *source;
- + guint id;
- +
- + g_return_val_if_fail (channel != NULL, 0);
- +
- + source = g_io_create_watch (channel, condition);
- +
- + if (priority != G_PRIORITY_DEFAULT)
- + g_source_set_priority (source, priority);
- + g_source_set_callback (source, (GSourceFunc)func, user_data, notify);
- +
- + id = g_source_attach (source, NULL);
- + g_source_unref (source);
- +
- + return id;
- +}
- +
- +guint
- +g_io_add_watch (GIOChannel *channel,
- + GIOCondition condition,
- + GIOFunc func,
- + gpointer user_data)
- +{
- + 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 whether there
- + * is data to be read/space to write data in 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)
- +{
- + GIOCondition condition = 0;
- +
- + if (channel->encoding)
- + {
- + if (channel->encoded_read_buf && (channel->encoded_read_buf->len > 0))
- + condition |= G_IO_IN; /* Only return if we have full characters */
- + }
- + else
- + {
- + if (channel->read_buf && (channel->read_buf->len > 0))
- + condition |= G_IO_IN;
- + }
- +
- + if (channel->write_buf && (channel->write_buf->len < channel->buf_size))
- + condition |= G_IO_OUT;
- +
- + return condition;
- +}
- +
- +/**
- + * g_io_channel_error_from_errno:
- + * @en: an <literal>errno</literal> error number, e.g. %EINVAL
- + *
- + * Converts an <literal>errno</literal> error number to a #GIOChannelError.
- + *
- + * Return value: a #GIOChannelError error number, e.g.
- + * %G_IO_CHANNEL_ERROR_INVAL.
- + **/
- +GIOChannelError
- +g_io_channel_error_from_errno (gint en)
- +{
- +#ifdef EAGAIN
- + g_return_val_if_fail (en != EAGAIN, G_IO_CHANNEL_ERROR_FAILED);
- +#endif
- +
- + switch (en)
- + {
- +#ifdef EBADF
- + case EBADF:
- + g_warning("Invalid file descriptor.\n");
- + return G_IO_CHANNEL_ERROR_FAILED;
- +#endif
- +
- +#ifdef EFAULT
- + case EFAULT:
- + g_warning("Buffer outside valid address space.\n");
- + return G_IO_CHANNEL_ERROR_FAILED;
- +#endif
- +
- +#ifdef EFBIG
- + case EFBIG:
- + return G_IO_CHANNEL_ERROR_FBIG;
- +#endif
- +
- +#ifdef EINTR
- + /* In general, we should catch EINTR before we get here,
- + * but close() is allowed to return EINTR by POSIX, so
- + * we need to catch it here; EINTR from close() is
- + * unrecoverable, because it's undefined whether
- + * the fd was actually closed or not, so we just return
- + * a generic error code.
- + */
- + case EINTR:
- + return G_IO_CHANNEL_ERROR_FAILED;
- +#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 ENOSPC
- + case ENOSPC:
- + return G_IO_CHANNEL_ERROR_NOSPC;
- +#endif
- +
- +#ifdef ENXIO
- + case ENXIO:
- + return G_IO_CHANNEL_ERROR_NXIO;
- +#endif
- +
- +#ifdef EOVERFLOW
- + case EOVERFLOW:
- + return G_IO_CHANNEL_ERROR_OVERFLOW;
- +#endif
- +
- +#ifdef EPIPE
- + case EPIPE:
- + return G_IO_CHANNEL_ERROR_PIPE;
- +#endif
- +
- + default:
- + return G_IO_CHANNEL_ERROR_FAILED;
- + }
- +}
- +
- +/**
- + * g_io_channel_set_buffer_size:
- + * @channel: a #GIOChannel
- + * @size: the size of the buffer, or 0 to let GLib pick a good size
- + *
- + * Sets 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;
- +
- + if (size < MAX_CHAR_SIZE)
- + size = MAX_CHAR_SIZE;
- +
- + channel->buf_size = size;
- +}
- +
- +/**
- + * g_io_channel_get_buffer_size:
- + * @channel: a #GIOChannel
- + *
- + * Gets 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 autodetect.
- + * Autodetection breaks on "\n", "\r\n", "\r", "\0", and
- + * the Unicode paragraph separator. Autodetection should
- + * not be used for anything other than file-based channels.
- + * @length: The length of the termination string. If -1 is passed, the
- + * string is assumed to be nul-terminated. This option allows
- + * termination strings with embedded nuls.
- + *
- + * 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,
- + gint length)
- +{
- + g_return_if_fail (channel != NULL);
- + g_return_if_fail (line_term == NULL || length != 0); /* Disallow "" */
- +
- + if (line_term == NULL)
- + length = 0;
- + else if (length < 0)
- + length = strlen (line_term);
- +
- + g_free (channel->line_term);
- + channel->line_term = line_term ? g_memdup (line_term, length) : NULL;
- + channel->line_term_len = length;
- +}
- +
- +/**
- + * g_io_channel_get_line_term:
- + * @channel: a #GIOChannel
- + * @length: a location to return the length of the line terminator
- + *
- + * This returns the string that #GIOChannel uses to determine
- + * where in the file a line break occurs. A value of %NULL
- + * indicates autodetection.
- + *
- + * 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,
- + gint *length)
- +{
- + g_return_val_if_fail (channel != NULL, NULL);
- +
- + if (length)
- + *length = channel->line_term_len;
- +
- + return channel->line_term;
- +}
- +
- +/**
- + * g_io_channel_set_flags:
- + * @channel: a #GIOChannel
- + * @flags: the flags to set on the IO channel
- + * @error: A location to return an error of type #GIOChannelError
- + *
- + * Sets the (writeable) flags in @channel to (@flags & %G_IO_CHANNEL_SET_MASK).
- + *
- + * Return value: the status of the operation.
- + **/
- +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
- + *
- + * Gets the current flags for a #GIOChannel, including read-only
- + * flags such as %G_IO_FLAG_IS_READABLE.
- + *
- + * The values of the flags %G_IO_FLAG_IS_READABLE and %G_IO_FLAG_IS_WRITEABLE
- + * are cached for internal use by the channel when it is created.
- + * If they should change at some later point (e.g. partial shutdown
- + * of a socket with the UNIX shutdown() function), the user
- + * should immediately call g_io_channel_get_flags() to update
- + * the internal values of these flags.
- + *
- + * Return value: the flags which are set on the channel
- + **/
- +GIOFlags
- +g_io_channel_get_flags (GIOChannel *channel)
- +{
- + GIOFlags flags;
- +
- + g_return_val_if_fail (channel != NULL, 0);
- +
- + flags = (* channel->funcs->io_get_flags) (channel);
- +
- + /* Cross implementation code */
- +
- + if (channel->is_seekable)
- + flags |= G_IO_FLAG_IS_SEEKABLE;
- + if (channel->is_readable)
- + flags |= G_IO_FLAG_IS_READABLE;
- + if (channel->is_writeable)
- + flags |= G_IO_FLAG_IS_WRITEABLE;
- +
- + return flags;
- +}
- +
- +/**
- + * g_io_channel_set_close_on_unref:
- + * @channel: a #GIOChannel
- + * @do_close: Whether to close the channel on the final unref of
- + * the GIOChannel data structure. The default value of
- + * this is %TRUE for channels created by g_io_channel_new_file (),
- + * and %FALSE for all other channels.
- + *
- + * Setting this flag to %TRUE for a channel you have already closed
- + * can cause problems.
- + **/
- +void
- +g_io_channel_set_close_on_unref (GIOChannel *channel,
- + gboolean do_close)
- +{
- + g_return_if_fail (channel != NULL);
- +
- + channel->close_on_unref = do_close;
- +}
- +
- +/**
- + * g_io_channel_get_close_on_unref:
- + * @channel: a #GIOChannel.
- + *
- + * Returns whether the file/socket/whatever associated with @channel
- + * will be closed when @channel receives its final unref and is
- + * destroyed. The default value of this is %TRUE for channels created
- + * by g_io_channel_new_file (), and %FALSE for all other channels.
- + *
- + * Return value: Whether the channel will be closed on the final unref of
- + * the GIOChannel data structure.
- + **/
- +gboolean
- +g_io_channel_get_close_on_unref (GIOChannel *channel)
- +{
- + g_return_val_if_fail (channel != NULL, FALSE);
- +
- + return channel->close_on_unref;
- +}
- +
- +/**
- + * 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 in those
- + * cases where a call to g_io_channel_set_encoding ()
- + * is allowed. See the documentation for
- + * g_io_channel_set_encoding () for details.
- + * @error: A location to return an error of type #GIOChannelError
- + *
- + * Replacement for g_io_channel_seek() with the new API.
- + *
- + * Return value: the status of the operation.
- + **/
- +GIOStatus
- +g_io_channel_seek_position (GIOChannel *channel,
- + gint64 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);
- + g_return_val_if_fail (channel->is_seekable, G_IO_STATUS_ERROR);
- +
- + switch (type)
- + {
- + case G_SEEK_CUR: /* The user is seeking relative to the head of the buffer */
- + if (channel->use_buffer)
- + {
- + if (channel->do_encode && channel->encoded_read_buf
- + && channel->encoded_read_buf->len > 0)
- + {
- + g_warning ("Seek type G_SEEK_CUR not allowed for this"
- + " channel's encoding.\n");
- + return G_IO_STATUS_ERROR;
- + }
- + if (channel->read_buf)
- + offset -= channel->read_buf->len;
- + if (channel->encoded_read_buf)
- + {
- + g_assert (channel->encoded_read_buf->len == 0 || !channel->do_encode);
- +
- + /* If there's anything here, it's because the encoding is UTF-8,
- + * so we can just subtract the buffer length, the same as for
- + * the unencoded data.
- + */
- +
- + offset -= channel->encoded_read_buf->len;
- + }
- + }
- + 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;
- + }
- +
- + if (channel->use_buffer)
- + {
- + status = g_io_channel_flush (channel, error);
- + if (status != G_IO_STATUS_NORMAL)
- + return status;
- + }
- +
- + status = channel->funcs->io_seek (channel, offset, type, error);
- +
- + if ((status == G_IO_STATUS_NORMAL) && (channel->use_buffer))
- + {
- + if (channel->read_buf)
- + g_string_truncate (channel->read_buf, 0);
- +
- + /* Conversion state no longer matches position in file */
- + if (channel->read_cd != (GIConv) -1)
- + g_iconv (channel->read_cd, NULL, NULL, NULL, NULL);
- + if (channel->write_cd != (GIConv) -1)
- + g_iconv (channel->write_cd, NULL, NULL, NULL, NULL);
- +
- + if (channel->encoded_read_buf)
- + {
- + g_assert (channel->encoded_read_buf->len == 0 || !channel->do_encode);
- + g_string_truncate (channel->encoded_read_buf, 0);
- + }
- +
- + if (channel->partial_write_buf[0] != '\0')
- + {
- + g_warning ("Partial character at end of write buffer not flushed.\n");
- + channel->partial_write_buf[0] = '\0';
- + }
- + }
- +
- + return status;
- +}
- +
- +/**
- + * g_io_channel_flush:
- + * @channel: a #GIOChannel
- + * @error: location to store an error of type #GIOChannelError
- + *
- + * Flushes 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 = 1, 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 == NULL || channel->write_buf->len == 0)
- + return G_IO_STATUS_NORMAL;
- +
- + do
- + {
- + g_assert (this_time > 0);
- +
- + 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));
- +
- + g_string_erase (channel->write_buf, 0, bytes_written);
- +
- + return status;
- +}
- +
- +/**
- + * g_io_channel_set_buffered:
- + * @channel: a #GIOChannel
- + * @buffered: whether to set the channel buffered or unbuffered
- + *
- + * The buffering state can only be set if the channel's encoding
- + * is %NULL. For any other encoding, the channel must be buffered.
- + *
- + * A buffered channel can only be set unbuffered if the channel's
- + * internal buffers have been flushed. Newly created channels or
- + * channels which have returned %G_IO_STATUS_EOF
- + * not require such a flush. For write-only channels, a call to
- + * g_io_channel_flush () is sufficient. For all other channels,
- + * the buffers may be flushed by a call to g_io_channel_seek_position ().
- + * This includes the possibility of seeking with seek type %G_SEEK_CUR
- + * and an offset of zero. Note that this means that socket-based
- + * channels cannot be set unbuffered once they have had data
- + * read from them.
- + *
- + * On unbuffered channels, it is safe to mix read and write
- + * calls from the new and old APIs, if this is necessary for
- + * maintaining old code.
- + *
- + * The default state of the channel is buffered.
- + **/
- +void
- +g_io_channel_set_buffered (GIOChannel *channel,
- + gboolean buffered)
- +{
- + g_return_if_fail (channel != NULL);
- +
- + if (channel->encoding != NULL)
- + {
- + g_warning ("Need to have NULL encoding to set the buffering state of the "
- + "channel.\n");
- + return;
- + }
- +
- + g_return_if_fail (!channel->read_buf || channel->read_buf->len == 0);
- + g_return_if_fail (!channel->write_buf || channel->write_buf->len == 0);
- +
- + channel->use_buffer = buffered;
- +}
- +
- +/**
- + * g_io_channel_get_buffered:
- + * @channel: a #GIOChannel
- + *
- + * Returns whether @channel is buffered.
- + *
- + * Return Value: %TRUE if the @channel is buffered.
- + **/
- +gboolean
- +g_io_channel_get_buffered (GIOChannel *channel)
- +{
- + g_return_val_if_fail (channel != NULL, FALSE);
- +
- + return channel->use_buffer;
- +}
- +
- +/**
- + * g_io_channel_set_encoding:
- + * @channel: a #GIOChannel
- + * @encoding: the encoding type
- + * @error: location to store an error of type #GConvertError
- + *
- + * Sets the encoding for the input/output of the channel.
- + * The internal encoding is always UTF-8. The default encoding
- + * for the external file is UTF-8.
- + *
- + * The encoding %NULL is safe to use with binary data.
- + *
- + * The encoding can only be set if one of the following conditions
- + * is true:
- + * <itemizedlist>
- + * <listitem><para>
- + * The channel was just created, and has not been written to or read
- + * from yet.
- + * </para></listitem>
- + * <listitem><para>
- + * The channel is write-only.
- + * </para></listitem>
- + * <listitem><para>
- + * 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.)
- + * </para></listitem>
- + * <listitem><para>
- + * The current encoding is %NULL or UTF-8.
- + * </para></listitem>
- + * <listitem><para>
- + * One of the (new API) read functions has just returned %G_IO_STATUS_EOF
- + * (or, in the case of g_io_channel_read_to_end(), %G_IO_STATUS_NORMAL).
- + * </para></listitem>
- + * <listitem><para>
- + * One of the functions g_io_channel_read_chars() or
- + * g_io_channel_read_unichar() has returned %G_IO_STATUS_AGAIN or
- + * %G_IO_STATUS_ERROR. This may be useful in the case of
- + * %G_CONVERT_ERROR_ILLEGAL_SEQUENCE.
- + * Returning one of these statuses from g_io_channel_read_line(),
- + * g_io_channel_read_line_string(), or g_io_channel_read_to_end()
- + * does <emphasis>not</emphasis> guarantee that the encoding can
- + * be changed.
- + * </para></listitem>
- + * </itemizedlist>
- + * Channels which do not meet one of the above conditions cannot call
- + * g_io_channel_seek_position() with an offset of %G_SEEK_CUR, and, if
- + * they are "seekable", cannot call g_io_channel_write_chars() after
- + * calling one of the API "read" functions.
- + *
- + * Return Value: %G_IO_STATUS_NORMAL if the encoding was successfully 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 encoded buffers are empty */
- +
- + g_return_val_if_fail (!channel->do_encode || !channel->encoded_read_buf ||
- + channel->encoded_read_buf->len == 0, G_IO_STATUS_ERROR);
- +
- + if (!channel->use_buffer)
- + {
- + g_warning ("Need to set the channel buffered before setting the encoding.\n");
- + g_warning ("Assuming this is what you meant and acting accordingly.\n");
- +
- + channel->use_buffer = TRUE;
- + }
- +
- + if (channel->partial_write_buf[0] != '\0')
- + {
- + g_warning ("Partial character at end of write buffer not flushed.\n");
- + channel->partial_write_buf[0] = '\0';
- + }
- +
- + did_encode = channel->do_encode;
- +
- + if (!encoding || strcmp (encoding, "UTF8") == 0 || strcmp (encoding, "UTF-8") == 0)
- + {
- + channel->do_encode = FALSE;
- + read_cd = write_cd = (GIConv) -1;
- + }
- + else
- + {
- + gint err = 0;
- + const gchar *from_enc = NULL, *to_enc = NULL;
- +
- + if (channel->is_readable)
- + {
- + read_cd = g_iconv_open ("UTF-8", encoding);
- +
- + if (read_cd == (GIConv) -1)
- + {
- + err = errno;
- + from_enc = encoding;
- + to_enc = "UTF-8";
- + }
- + }
- + else
- + read_cd = (GIConv) -1;
- +
- + if (channel->is_writeable && err == 0)
- + {
- + write_cd = g_iconv_open (encoding, "UTF-8");
- +
- + if (write_cd == (GIConv) -1)
- + {
- + err = errno;
- + from_enc = "UTF-8";
- + to_enc = encoding;
- + }
- + }
- + else
- + write_cd = (GIConv) -1;
- +
- + if (err != 0)
- + {
- + g_assert (from_enc);
- + g_assert (to_enc);
- +
- + 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, g_strerror (err));
- +
- + if (read_cd != (GIConv) -1)
- + g_iconv_close (read_cd);
- + if (write_cd != (GIConv) -1)
- + g_iconv_close (write_cd);
- +
- + return G_IO_STATUS_ERROR;
- + }
- +
- + channel->do_encode = TRUE;
- + }
- +
- + /* The encoding is ok, so set the fields in channel */
- +
- + if (channel->read_cd != (GIConv) -1)
- + g_iconv_close (channel->read_cd);
- + if (channel->write_cd != (GIConv) -1)
- + g_iconv_close (channel->write_cd);
- +
- + if (channel->encoded_read_buf && channel->encoded_read_buf->len > 0)
- + {
- + g_assert (!did_encode); /* Encoding UTF-8, NULL doesn't use encoded_read_buf */
- +
- + /* This is just validated UTF-8, so we can copy it back into read_buf
- + * so it can be encoded in whatever the new encoding is.
- + */
- +
- + g_string_prepend_len (channel->read_buf, channel->encoded_read_buf->str,
- + channel->encoded_read_buf->len);
- + g_string_truncate (channel->encoded_read_buf, 0);
- + }
- +
- + 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
- + *
- + * Gets the encoding for the input/output of the channel.
- + * The internal encoding is always UTF-8. The encoding %NULL
- + * makes the channel safe for 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->is_seekable && channel->write_buf && channel->write_buf->len > 0)
- + {
- + status = g_io_channel_flush (channel, err);
- + if (status != G_IO_STATUS_NORMAL)
- + return status;
- + }
- + if (channel->is_seekable && channel->partial_write_buf[0] != '\0')
- + {
- + g_warning ("Partial character at end of write buffer not flushed.\n");
- + channel->partial_write_buf[0] = '\0';
- + }
- +
- + if (!channel->read_buf)
- + channel->read_buf = g_string_sized_new (channel->buf_size);
- +
- + 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->encoded_read_buf)
- + oldlen = channel->encoded_read_buf->len;
- + else
- + {
- + oldlen = 0;
- + if (channel->encoding)
- + channel->encoded_read_buf = g_string_sized_new (channel->buf_size);
- + }
- +
- + if (channel->do_encode)
- + {
- + gsize errnum, inbytes_left, outbytes_left;
- + gchar *inbuf, *outbuf;
- + int errval;
- +
- + g_assert (channel->encoded_read_buf);
- +
- +reencode:
- +
- + inbytes_left = channel->read_buf->len;
- + outbytes_left = MAX (channel->read_buf->len,
- + channel->encoded_read_buf->allocated_len
- + - channel->encoded_read_buf->len - 1); /* 1 for NULL */
- + outbytes_left = MAX (outbytes_left, 6);
- +
- + inbuf = channel->read_buf->str;
- + g_string_set_size (channel->encoded_read_buf,
- + channel->encoded_read_buf->len + outbytes_left);
- + 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);
- + errval = errno;
- +
- + g_assert (inbuf + inbytes_left == channel->read_buf->str
- + + channel->read_buf->len);
- + g_assert (outbuf + outbytes_left == channel->encoded_read_buf->str
- + + channel->encoded_read_buf->len);
- +
- + 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 == (gsize) -1)
- + {
- + switch (errval)
- + {
- + case EINVAL:
- + if ((oldlen == channel->encoded_read_buf->len)
- + && (status == G_IO_STATUS_EOF))
- + status = G_IO_STATUS_EOF;
- + else
- + status = G_IO_STATUS_NORMAL;
- + break;
- + case E2BIG:
- + /* Buffer size at least 6, wrote at least on character */
- + g_assert (inbuf != channel->read_buf->str);
- + 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_assert (errval != EBADF); /* The converter should be open */
- + g_set_error (err, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
- + _("Error during conversion: %s"), g_strerror (errval));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- + g_assert ((status != G_IO_STATUS_NORMAL)
- + || (channel->encoded_read_buf->len > 0));
- + }
- + else if (channel->encoding) /* UTF-8 */
- + {
- + gchar *nextchar, *lastchar;
- +
- + g_assert (channel->encoded_read_buf);
- +
- + nextchar = channel->read_buf->str;
- + lastchar = channel->read_buf->str + channel->read_buf->len;
- +
- + while (nextchar < lastchar)
- + {
- + gunichar val_char;
- +
- + val_char = g_utf8_get_char_validated (nextchar, lastchar - nextchar);
- +
- + switch (val_char)
- + {
- + case -2:
- + /* stop, leave partial character in buffer */
- + lastchar = nextchar;
- + break;
- + case -1:
- + 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"));
- + status = G_IO_STATUS_ERROR;
- + }
- + lastchar = nextchar;
- + break;
- + default:
- + nextchar = g_utf8_next_char (nextchar);
- + break;
- + }
- + }
- +
- + if (lastchar > channel->read_buf->str)
- + {
- + gint copy_len = lastchar - channel->read_buf->str;
- +
- + g_string_append_len (channel->encoded_read_buf, channel->read_buf->str,
- + copy_len);
- + g_string_erase (channel->read_buf, 0, copy_len);
- + }
- + }
- +
- + return status;
- +}
- +
- +/**
- + * g_io_channel_read_line:
- + * @channel: a #GIOChannel
- + * @str_return: The line read from the #GIOChannel, including the
- + * line terminator. This data should be freed with g_free()
- + * when no longer needed. This is a nul-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
- + *
- + * Reads a line, including the terminating character(s),
- + * from a #GIOChannel into a newly-allocated string.
- + * @str_return will contain allocated memory if the return
- + * is %G_IO_STATUS_NORMAL.
- + *
- + * Return value: the status of the operation.
- + **/
- +GIOStatus
- +g_io_channel_read_line (GIOChannel *channel,
- + gchar **str_return,
- + gsize *length,
- + gsize *terminator_pos,
- + GError **error)
- +{
- + GIOStatus status;
- + gsize got_length;
- +
- + 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);
- + g_return_val_if_fail (channel->is_readable, G_IO_STATUS_ERROR);
- +
- + status = g_io_channel_read_line_backend (channel, &got_length, terminator_pos, error);
- +
- + if (length)
- + *length = got_length;
- +
- + if (status == G_IO_STATUS_NORMAL)
- + {
- + g_assert (USE_BUF (channel));
- + *str_return = g_strndup (USE_BUF (channel)->str, got_length);
- + g_string_erase (USE_BUF (channel), 0, got_length);
- + }
- + else
- + *str_return = NULL;
- +
- + 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 old data will
- + * be overwritten.
- + * @terminator_pos: location to store position of line terminator, or %NULL
- + * @error: a location to store an error of type #GConvertError
- + * or #GIOChannelError
- + *
- + * Reads a line from a #GIOChannel, using a #GString as a buffer.
- + *
- + * Return value: the status of the operation.
- + **/
- +GIOStatus
- +g_io_channel_read_line_string (GIOChannel *channel,
- + GString *buffer,
- + gsize *terminator_pos,
- + GError **error)
- +{
- + gsize length;
- + GIOStatus status;
- +
- + 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);
- + g_return_val_if_fail (channel->is_readable, G_IO_STATUS_ERROR);
- +
- + if (buffer->len > 0)
- + g_string_truncate (buffer, 0); /* clear out the buffer */
- +
- + status = g_io_channel_read_line_backend (channel, &length, terminator_pos, error);
- +
- + if (status == G_IO_STATUS_NORMAL)
- + {
- + g_assert (USE_BUF (channel));
- + g_string_append_len (buffer, USE_BUF (channel)->str, length);
- + g_string_erase (USE_BUF (channel), 0, length);
- + }
- +
- + return status;
- +}
- +
- +
- +static GIOStatus
- +g_io_channel_read_line_backend (GIOChannel *channel,
- + gsize *length,
- + gsize *terminator_pos,
- + GError **error)
- +{
- + GIOStatus status;
- + gsize checked_to, line_term_len, line_length, got_term_len;
- + gboolean first_time = TRUE;
- +
- + 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;
- + }
- +
- + status = G_IO_STATUS_NORMAL;
- +
- + if (channel->line_term)
- + line_term_len = channel->line_term_len;
- + else
- + line_term_len = 3;
- + /* This value used for setting checked_to, it's the longest of the four
- + * we autodetect for.
- + */
- +
- + checked_to = 0;
- +
- + while (TRUE)
- + {
- + gchar *nextchar, *lastchar;
- + GString *use_buf;
- +
- + if (!first_time || (BUF_LEN (USE_BUF (channel)) == 0))
- + {
- +read_again:
- + status = g_io_channel_fill_buffer (channel, error);
- + switch (status)
- + {
- + case G_IO_STATUS_NORMAL:
- + if (BUF_LEN (USE_BUF (channel)) == 0)
- + /* Can happen when using conversion and only read
- + * part of a character
- + */
- + {
- + first_time = FALSE;
- + continue;
- + }
- + break;
- + case G_IO_STATUS_EOF:
- + if (BUF_LEN (USE_BUF (channel)) == 0)
- + {
- + if (length)
- + *length = 0;
- +
- + if (channel->encoding && channel->read_buf->len != 0)
- + {
- + g_set_error (error, G_CONVERT_ERROR,
- + G_CONVERT_ERROR_PARTIAL_INPUT,
- + _("Leftover unconverted data in read buffer"));
- + return G_IO_STATUS_ERROR;
- + }
- + else
- + return G_IO_STATUS_EOF;
- + }
- + break;
- + default:
- + if (length)
- + *length = 0;
- + return status;
- + }
- + }
- +
- + g_assert (BUF_LEN (USE_BUF (channel)) != 0);
- +
- + use_buf = USE_BUF (channel); /* The buffer has been created by this point */
- +
- + first_time = FALSE;
- +
- + lastchar = use_buf->str + use_buf->len;
- +
- + for (nextchar = use_buf->str + checked_to; nextchar < lastchar;
- + channel->encoding ? nextchar = g_utf8_next_char (nextchar) : nextchar++)
- + {
- + if (channel->line_term)
- + {
- + if (memcmp (channel->line_term, nextchar, line_term_len) == 0)
- + {
- + line_length = nextchar - use_buf->str;
- + got_term_len = line_term_len;
- + goto done;
- + }
- + }
- + else /* auto detect */
- + {
- + switch (*nextchar)
- + {
- + case '\n': /* unix */
- + line_length = nextchar - use_buf->str;
- + got_term_len = 1;
- + goto done;
- + case '\r': /* Warning: do not use with sockets */
- + line_length = nextchar - use_buf->str;
- + if ((nextchar == lastchar - 1) && (status != G_IO_STATUS_EOF)
- + && (lastchar == use_buf->str + use_buf->len))
- + goto read_again; /* Try to read more data */
- + if ((nextchar < lastchar - 1) && (*(nextchar + 1) == '\n')) /* dos */
- + got_term_len = 2;
- + else /* mac */
- + got_term_len = 1;
- + goto done;
- + case '\xe2': /* Unicode paragraph separator */
- + if (strncmp ("\xe2\x80\xa9", nextchar, 3) == 0)
- + {
- + line_length = nextchar - use_buf->str;
- + got_term_len = 3;
- + goto done;
- + }
- + break;
- + case '\0': /* Embeded null in input */
- + line_length = nextchar - use_buf->str;
- + got_term_len = 1;
- + goto done;
- + default: /* no match */
- + break;
- + }
- + }
- + }
- +
- + /* If encoding != NULL, valid UTF-8, didn't overshoot */
- + g_assert (nextchar == lastchar);
- +
- + /* Check for EOF */
- +
- + if (status == G_IO_STATUS_EOF)
- + {
- + if (channel->encoding && channel->read_buf->len > 0)
- + {
- + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
- + _("Channel terminates in a partial character"));
- + return G_IO_STATUS_ERROR;
- + }
- + line_length = use_buf->len;
- + got_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;
- + }
- +
- +done:
- +
- + if (terminator_pos)
- + *terminator_pos = line_length;
- +
- + if (length)
- + *length = line_length + got_term_len;
- +
- + 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 nul character, but there
- + * may be other nuls in the intervening data.
- + * @length: location to store length of the data
- + * @error: location to return an error of type #GConvertError
- + * or #GIOChannelError
- + *
- + * Reads all the remaining data from the file.
- + *
- + * Return value: %G_IO_STATUS_NORMAL on success.
- + * This function never returns %G_IO_STATUS_EOF.
- + **/
- +GIOStatus
- +g_io_channel_read_to_end (GIOChannel *channel,
- + gchar **str_return,
- + gsize *length,
- + GError **error)
- +{
- + GIOStatus status;
- +
- + 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 (channel->is_readable, G_IO_STATUS_ERROR);
- +
- + if (str_return)
- + *str_return = NULL;
- + if (length)
- + *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)
- + return status;
- +
- + if (channel->encoding && channel->read_buf->len > 0)
- + {
- + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_PARTIAL_INPUT,
- + _("Channel terminates in a partial character"));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + if (USE_BUF (channel) == NULL)
- + {
- + /* length is already set to zero */
- + if (str_return)
- + *str_return = g_strdup ("");
- + }
- + else
- + {
- + if (length)
- + *length = USE_BUF (channel)->len;
- +
- + if (str_return)
- + *str_return = g_string_free (USE_BUF (channel), FALSE);
- + else
- + g_string_free (USE_BUF (channel), TRUE);
- +
- + if (channel->encoding)
- + channel->encoded_read_buf = NULL;
- + else
- + channel->read_buf = NULL;
- + }
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +/**
- + * 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. This may be zero even on
- + * success if count < 6 and the channel's encoding is non-%NULL.
- + * This indicates that the next UTF-8 character is too wide for
- + * the buffer.
- + * @error: a location to return an error of type #GConvertError
- + * or #GIOChannelError.
- + *
- + * Replacement for g_io_channel_read() with the new API.
- + *
- + * Return value: the status of the operation.
- + **/
- +GIOStatus
- +g_io_channel_read_chars (GIOChannel *channel,
- + gchar *buf,
- + gsize count,
- + gsize *bytes_read,
- + GError **error)
- +{
- + GIOStatus status;
- + gsize got_bytes;
- +
- + 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 (channel->is_readable, 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)
- + {
- + gsize tmp_bytes;
- +
- + g_assert (!channel->read_buf || channel->read_buf->len == 0);
- +
- + status = channel->funcs->io_read (channel, buf, count, &tmp_bytes, error);
- +
- + if (bytes_read)
- + *bytes_read = tmp_bytes;
- +
- + return status;
- + }
- +
- + status = G_IO_STATUS_NORMAL;
- +
- + while (BUF_LEN (USE_BUF (channel)) < count && status == G_IO_STATUS_NORMAL)
- + status = g_io_channel_fill_buffer (channel, error);
- +
- + /* Only return an error if we have no data */
- +
- + if (BUF_LEN (USE_BUF (channel)) == 0)
- + {
- + g_assert (status != G_IO_STATUS_NORMAL);
- +
- + if (status == G_IO_STATUS_EOF && channel->encoding
- + && BUF_LEN (channel->read_buf) > 0)
- + {
- + g_set_error (error, G_CONVERT_ERROR,
- + G_CONVERT_ERROR_PARTIAL_INPUT,
- + _("Leftover unconverted data in read buffer"));
- + status = G_IO_STATUS_ERROR;
- + }
- +
- + if (bytes_read)
- + *bytes_read = 0;
- +
- + return status;
- + }
- +
- + if (status == G_IO_STATUS_ERROR)
- + g_clear_error (error);
- +
- + got_bytes = MIN (count, BUF_LEN (USE_BUF (channel)));
- +
- + g_assert (got_bytes > 0);
- +
- + if (channel->encoding)
- + /* Don't validate for NULL encoding, binary safe */
- + {
- + gchar *nextchar, *prevchar;
- +
- + g_assert (USE_BUF (channel) == channel->encoded_read_buf);
- +
- + nextchar = channel->encoded_read_buf->str;
- +
- + do
- + {
- + prevchar = nextchar;
- + nextchar = g_utf8_next_char (nextchar);
- + g_assert (nextchar != prevchar); /* Possible for *prevchar of -1 or -2 */
- + }
- + while (nextchar < channel->encoded_read_buf->str + got_bytes);
- +
- + if (nextchar > channel->encoded_read_buf->str + got_bytes)
- + got_bytes = prevchar - channel->encoded_read_buf->str;
- +
- + g_assert (got_bytes > 0 || count < 6);
- + }
- +
- + memcpy (buf, USE_BUF (channel)->str, got_bytes);
- + g_string_erase (USE_BUF (channel), 0, got_bytes);
- +
- + if (bytes_read)
- + *bytes_read = got_bytes;
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +/**
- + * g_io_channel_read_unichar:
- + * @channel: a #GIOChannel
- + * @thechar: a location to return a character
- + * @error: a location to return an error of type #GConvertError
- + * or #GIOChannelError
- + *
- + * Reads a Unicode character from @channel.
- + * This function cannot be called on a channel with %NULL encoding.
- + *
- + * Return value: a #GIOStatus
- + **/
- +GIOStatus
- +g_io_channel_read_unichar (GIOChannel *channel,
- + gunichar *thechar,
- + GError **error)
- +{
- + GIOStatus status = G_IO_STATUS_NORMAL;
- +
- + g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
- + g_return_val_if_fail (channel->encoding != NULL, G_IO_STATUS_ERROR);
- + g_return_val_if_fail ((error == NULL) || (*error == NULL),
- + G_IO_STATUS_ERROR);
- + g_return_val_if_fail (channel->is_readable, G_IO_STATUS_ERROR);
- +
- + while (BUF_LEN (channel->encoded_read_buf) == 0 && status == G_IO_STATUS_NORMAL)
- + status = g_io_channel_fill_buffer (channel, error);
- +
- + /* Only return an error if we have no data */
- +
- + if (BUF_LEN (USE_BUF (channel)) == 0)
- + {
- + g_assert (status != G_IO_STATUS_NORMAL);
- +
- + if (status == G_IO_STATUS_EOF && BUF_LEN (channel->read_buf) > 0)
- + {
- + g_set_error (error, G_CONVERT_ERROR,
- + G_CONVERT_ERROR_PARTIAL_INPUT,
- + _("Leftover unconverted data in read buffer"));
- + status = G_IO_STATUS_ERROR;
- + }
- +
- + if (thechar)
- + *thechar = (gunichar) -1;
- +
- + return status;
- + }
- +
- + if (status == G_IO_STATUS_ERROR)
- + g_clear_error (error);
- +
- + if (thechar)
- + *thechar = g_utf8_get_char (channel->encoded_read_buf->str);
- +
- + g_string_erase (channel->encoded_read_buf, 0,
- + g_utf8_next_char (channel->encoded_read_buf->str)
- + - channel->encoded_read_buf->str);
- +
- + 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. This can be nonzero
- + * even if the return value is not %G_IO_STATUS_NORMAL.
- + * If the return value is %G_IO_STATUS_NORMAL and the
- + * channel is blocking, this will always be equal
- + * to @count if @count >= 0.
- + * @error: a location to return an error of type #GConvertError
- + * or #GIOChannelError
- + *
- + * Replacement for g_io_channel_write() with the new API.
- + *
- + * On seekable channels with encodings other than %NULL or UTF-8, generic
- + * mixing of reading and writing is not allowed. A call to g_io_channel_write_chars ()
- + * may only be made on a channel from which data has been read in the
- + * cases described in the documentation for g_io_channel_set_encoding ().
- + *
- + * Return value: the status of the operation.
- + **/
- +GIOStatus
- +g_io_channel_write_chars (GIOChannel *channel,
- + const gchar *buf,
- + gssize count,
- + gsize *bytes_written,
- + GError **error)
- +{
- + GIOStatus status;
- + gssize wrote_bytes = 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);
- + g_return_val_if_fail (channel->is_writeable, G_IO_STATUS_ERROR);
- +
- + if ((count < 0) && buf)
- + count = strlen (buf);
- +
- + if (count == 0)
- + {
- + if (bytes_written)
- + *bytes_written = 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)
- + {
- + gsize tmp_bytes;
- +
- + g_assert (!channel->write_buf || channel->write_buf->len == 0);
- + g_assert (channel->partial_write_buf[0] == '\0');
- +
- + status = channel->funcs->io_write (channel, buf, count, &tmp_bytes, error);
- +
- + if (bytes_written)
- + *bytes_written = tmp_bytes;
- +
- + return status;
- + }
- +
- + /* General case */
- +
- + if (channel->is_seekable && (( BUF_LEN (channel->read_buf) > 0)
- + || (BUF_LEN (channel->encoded_read_buf) > 0)))
- + {
- + if (channel->do_encode && BUF_LEN (channel->encoded_read_buf) > 0)
- + {
- + g_warning("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)
- + {
- + if (bytes_written)
- + *bytes_written = 0;
- + return status;
- + }
- + }
- +
- + if (!channel->write_buf)
- + channel->write_buf = g_string_sized_new (channel->buf_size);
- +
- + while (wrote_bytes < count)
- + {
- + gsize space_in_buf;
- +
- + /* If the buffer is full, try a write immediately. In
- + * the nonblocking case, this prevents the user from
- + * writing just a little bit to the buffer every time
- + * and never receiving an EAGAIN.
- + */
- +
- + if (channel->write_buf->len >= channel->buf_size - MAX_CHAR_SIZE)
- + {
- + gsize did_write = 0, this_time;
- +
- + do
- + {
- + status = channel->funcs->io_write (channel, channel->write_buf->str
- + + did_write, channel->write_buf->len
- + - did_write, &this_time, error);
- + did_write += this_time;
- + }
- + while (status == G_IO_STATUS_NORMAL &&
- + did_write < MIN (channel->write_buf->len, MAX_CHAR_SIZE));
- +
- + g_string_erase (channel->write_buf, 0, did_write);
- +
- + if (status != G_IO_STATUS_NORMAL)
- + {
- + if (status == G_IO_STATUS_AGAIN && wrote_bytes > 0)
- + status = G_IO_STATUS_NORMAL;
- + if (bytes_written)
- + *bytes_written = wrote_bytes;
- + return status;
- + }
- + }
- +
- + space_in_buf = MAX (channel->buf_size, channel->write_buf->allocated_len - 1)
- + - channel->write_buf->len; /* 1 for NULL */
- +
- + /* This is only true because g_io_channel_set_buffer_size ()
- + * ensures that channel->buf_size >= MAX_CHAR_SIZE.
- + */
- + g_assert (space_in_buf >= MAX_CHAR_SIZE);
- +
- + if (!channel->encoding)
- + {
- + gssize write_this = MIN (space_in_buf, count - wrote_bytes);
- +
- + g_string_append_len (channel->write_buf, buf, write_this);
- + buf += write_this;
- + wrote_bytes += write_this;
- + }
- + else
- + {
- + const gchar *from_buf;
- + gsize from_buf_len, from_buf_old_len, left_len;
- + gsize err;
- + gint errnum;
- +
- + if (channel->partial_write_buf[0] != '\0')
- + {
- + g_assert (wrote_bytes == 0);
- +
- + from_buf = channel->partial_write_buf;
- + from_buf_old_len = strlen (channel->partial_write_buf);
- + g_assert (from_buf_old_len > 0);
- + from_buf_len = MIN (6, from_buf_old_len + count);
- +
- + memcpy (channel->partial_write_buf + from_buf_old_len, buf,
- + from_buf_len - from_buf_old_len);
- + }
- + else
- + {
- + from_buf = buf;
- + from_buf_len = count - wrote_bytes;
- + from_buf_old_len = 0;
- + }
- +
- +reconvert:
- +
- + if (!channel->do_encode) /* UTF-8 encoding */
- + {
- + const gchar *badchar;
- + gsize try_len = MIN (from_buf_len, space_in_buf);
- +
- + /* UTF-8, just validate, emulate g_iconv */
- +
- + if (!g_utf8_validate (from_buf, try_len, &badchar))
- + {
- + gunichar try_char;
- + gsize incomplete_len = from_buf + try_len - badchar;
- +
- + left_len = from_buf + from_buf_len - badchar;
- +
- + try_char = g_utf8_get_char_validated (badchar, incomplete_len);
- +
- + switch (try_char)
- + {
- + case -2:
- + g_assert (incomplete_len < 6);
- + if (try_len == from_buf_len)
- + {
- + errnum = EINVAL;
- + err = (gsize) -1;
- + }
- + else
- + {
- + errnum = 0;
- + err = (gsize) 0;
- + }
- + break;
- + case -1:
- + g_warning ("Invalid UTF-8 passed to g_io_channel_write_chars().");
- + /* FIXME bail here? */
- + errnum = EILSEQ;
- + err = (gsize) -1;
- + break;
- + default:
- + g_assert_not_reached ();
- + err = (gsize) -1;
- + errnum = 0; /* Don't confunse the compiler */
- + }
- + }
- + else
- + {
- + err = (gsize) 0;
- + errnum = 0;
- + left_len = from_buf_len - try_len;
- + }
- +
- + g_string_append_len (channel->write_buf, from_buf,
- + from_buf_len - left_len);
- + from_buf += from_buf_len - left_len;
- + }
- + else
- + {
- + gchar *outbuf;
- +
- + left_len = from_buf_len;
- + g_string_set_size (channel->write_buf, channel->write_buf->len
- + + space_in_buf);
- + outbuf = channel->write_buf->str + channel->write_buf->len
- + - space_in_buf;
- + err = g_iconv (channel->write_cd, (gchar **) &from_buf, &left_len,
- + &outbuf, &space_in_buf);
- + errnum = errno;
- + g_string_truncate (channel->write_buf, channel->write_buf->len
- + - space_in_buf);
- + }
- +
- + if (err == (gsize) -1)
- + {
- + switch (errnum)
- + {
- + case EINVAL:
- + g_assert (left_len < 6);
- +
- + if (from_buf_old_len == 0)
- + {
- + /* Not from partial_write_buf */
- +
- + memcpy (channel->partial_write_buf, from_buf, left_len);
- + channel->partial_write_buf[left_len] = '\0';
- + if (bytes_written)
- + *bytes_written = count;
- + return G_IO_STATUS_NORMAL;
- + }
- +
- + /* Working in partial_write_buf */
- +
- + if (left_len == from_buf_len)
- + {
- + /* Didn't convert anything, must still have
- + * less than a full character
- + */
- +
- + g_assert (count == from_buf_len - from_buf_old_len);
- +
- + channel->partial_write_buf[from_buf_len] = '\0';
- +
- + if (bytes_written)
- + *bytes_written = count;
- +
- + return G_IO_STATUS_NORMAL;
- + }
- +
- + g_assert (from_buf_len - left_len >= from_buf_old_len);
- +
- + /* We converted all the old data. This is fine */
- +
- + break;
- + case E2BIG:
- + if (from_buf_len == left_len)
- + {
- + /* Nothing was written, add enough space for
- + * at least one character.
- + */
- + space_in_buf += MAX_CHAR_SIZE;
- + goto reconvert;
- + }
- + break;
- + case EILSEQ:
- + g_set_error (error, G_CONVERT_ERROR,
- + G_CONVERT_ERROR_ILLEGAL_SEQUENCE,
- + _("Invalid byte sequence in conversion input"));
- + if (from_buf_old_len > 0 && from_buf_len == left_len)
- + g_warning ("Illegal sequence due to partial character "
- + "at the end of a previous write.\n");
- + else
- + wrote_bytes += from_buf_len - left_len - from_buf_old_len;
- + if (bytes_written)
- + *bytes_written = wrote_bytes;
- + channel->partial_write_buf[0] = '\0';
- + return G_IO_STATUS_ERROR;
- + default:
- + g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED,
- + _("Error during conversion: %s"), g_strerror (errnum));
- + if (from_buf_len >= left_len + from_buf_old_len)
- + wrote_bytes += from_buf_len - left_len - from_buf_old_len;
- + if (bytes_written)
- + *bytes_written = wrote_bytes;
- + channel->partial_write_buf[0] = '\0';
- + return G_IO_STATUS_ERROR;
- + }
- + }
- +
- + g_assert (from_buf_len - left_len >= from_buf_old_len);
- +
- + wrote_bytes += from_buf_len - left_len - from_buf_old_len;
- +
- + if (from_buf_old_len > 0)
- + {
- + /* We were working in partial_write_buf */
- +
- + buf += from_buf_len - left_len - from_buf_old_len;
- + channel->partial_write_buf[0] = '\0';
- + }
- + else
- + buf = from_buf;
- + }
- + }
- +
- + if (bytes_written)
- + *bytes_written = count;
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +/**
- + * g_io_channel_write_unichar:
- + * @channel: a #GIOChannel
- + * @thechar: a character
- + * @error: location to return an error of type #GConvertError
- + * or #GIOChannelError
- + *
- + * Writes a Unicode character to @channel.
- + * This function cannot be called on a channel with %NULL encoding.
- + *
- + * Return value: a #GIOStatus
- + **/
- +GIOStatus
- +g_io_channel_write_unichar (GIOChannel *channel,
- + gunichar thechar,
- + GError **error)
- +{
- + GIOStatus status;
- + gchar static_buf[6];
- + gsize char_len, wrote_len;
- +
- + g_return_val_if_fail (channel != NULL, G_IO_STATUS_ERROR);
- + g_return_val_if_fail (channel->encoding != NULL, G_IO_STATUS_ERROR);
- + g_return_val_if_fail ((error == NULL) || (*error == NULL),
- + G_IO_STATUS_ERROR);
- + g_return_val_if_fail (channel->is_writeable, G_IO_STATUS_ERROR);
- +
- + char_len = g_unichar_to_utf8 (thechar, static_buf);
- +
- + if (channel->partial_write_buf[0] != '\0')
- + {
- + g_warning ("Partial charater written before writing unichar.\n");
- + channel->partial_write_buf[0] = '\0';
- + }
- +
- + status = g_io_channel_write_chars (channel, static_buf,
- + char_len, &wrote_len, error);
- +
- + /* We validate UTF-8, so we can't get a partial write */
- +
- + g_assert (wrote_len == char_len || status != G_IO_STATUS_NORMAL);
- +
- + return status;
- +}
- +
- +/**
- + * g_io_channel_error_quark:
- + *
- + * Return value: the quark used as %G_IO_CHANNEL_ERROR
- + **/
- +GQuark
- +g_io_channel_error_quark (void)
- +{
- + return g_quark_from_static_string ("g-io-channel-error-quark");
- +}
- diff --git a/clients/Instantbird/giounix.c b/clients/Instantbird/giounix.c
- new file mode 100755
- index 0000000..87197ed
- --- /dev/null
- +++ b/clients/Instantbird/giounix.c
- @@ -0,0 +1,598 @@
- +/* GLIB - Library of useful routines for C programming
- + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- + *
- + * giounix.c: IO Channels using unix file descriptors
- + * Copyright 1998 Owen Taylor
- + *
- + * This library is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2 of the License, or (at your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with this library; if not, write to the
- + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- + * Boston, MA 02111-1307, USA.
- + */
- +
- +/*
- + * Modified by the GLib Team and others 1997-2000. See the AUTHORS
- + * file for a list of people on the GLib Team. See the ChangeLog
- + * files for a list of changes. These files are distributed with
- + * GLib at ftp://ftp.gtk.org/pub/gtk/.
- + */
- +
- +/*
- + * MT safe
- + */
- +
- +#include "config.h"
- +
- +#define _POSIX_SOURCE /* for SSIZE_MAX */
- +
- +#include <sys/types.h>
- +#include <sys/stat.h>
- +#include <stdio.h>
- +#include <unistd.h>
- +#include <errno.h>
- +#include <string.h>
- +#include <fcntl.h>
- +
- +#include "glib.h"
- +#include "galias.h"
- +
- +/*
- + * Unix IO Channels
- + */
- +
- +typedef struct _GIOUnixChannel GIOUnixChannel;
- +typedef struct _GIOUnixWatch GIOUnixWatch;
- +
- +struct _GIOUnixChannel
- +{
- + GIOChannel channel;
- + gint fd;
- +};
- +
- +struct _GIOUnixWatch
- +{
- + GSource source;
- + GPollFD pollfd;
- + 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,
- + gint64 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);
- +static gboolean g_io_unix_check (GSource *source);
- +static gboolean g_io_unix_dispatch (GSource *source,
- + GSourceFunc callback,
- + gpointer user_data);
- +static void g_io_unix_finalize (GSource *source);
- +
- +GSourceFuncs g_io_watch_funcs = {
- + g_io_unix_prepare,
- + g_io_unix_check,
- + g_io_unix_dispatch,
- + g_io_unix_finalize
- +};
- +
- +static GIOFuncs unix_channel_funcs = {
- + g_io_unix_read,
- + g_io_unix_write,
- + g_io_unix_seek,
- + 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;
- + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
- +
- + *timeout = -1;
- +
- + /* Only return TRUE here if _all_ bits in watch->condition will be set
- + */
- + return ((watch->condition & buffer_condition) == watch->condition);
- +}
- +
- +static gboolean
- +g_io_unix_check (GSource *source)
- +{
- + GIOUnixWatch *watch = (GIOUnixWatch *)source;
- + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
- + GIOCondition poll_condition = watch->pollfd.revents;
- +
- + return ((poll_condition | buffer_condition) & watch->condition);
- +}
- +
- +static gboolean
- +g_io_unix_dispatch (GSource *source,
- + GSourceFunc callback,
- + gpointer user_data)
- +
- +{
- + GIOFunc func = (GIOFunc)callback;
- + GIOUnixWatch *watch = (GIOUnixWatch *)source;
- + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
- +
- + if (!func)
- + {
- + g_warning ("IO watch dispatched without callback\n"
- + "You must call g_source_connect().");
- + return FALSE;
- + }
- +
- + return (*func) (watch->channel,
- + (watch->pollfd.revents | buffer_condition) & watch->condition,
- + user_data);
- +}
- +
- +static void
- +g_io_unix_finalize (GSource *source)
- +{
- + GIOUnixWatch *watch = (GIOUnixWatch *)source;
- +
- + g_io_channel_unref (watch->channel);
- +}
- +
- +static GIOStatus
- +g_io_unix_read (GIOChannel *channel,
- + gchar *buf,
- + gsize count,
- + gsize *bytes_read,
- + GError **err)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- + gssize result;
- +
- + if (count > SSIZE_MAX) /* At least according to the Debian manpage for read */
- + count = SSIZE_MAX;
- +
- + retry:
- + result = read (unix_channel->fd, buf, count);
- +
- + if (result < 0)
- + {
- + *bytes_read = 0;
- +
- + switch (errno)
- + {
- +#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_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- +
- + *bytes_read = result;
- +
- + return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
- +}
- +
- +static GIOStatus
- +g_io_unix_write (GIOChannel *channel,
- + const gchar *buf,
- + gsize count,
- + gsize *bytes_written,
- + GError **err)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- + gssize result;
- +
- + retry:
- + result = write (unix_channel->fd, buf, count);
- +
- + if (result < 0)
- + {
- + *bytes_written = 0;
- +
- + switch (errno)
- + {
- +#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_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- +
- + *bytes_written = result;
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GIOStatus
- +g_io_unix_seek (GIOChannel *channel,
- + gint64 offset,
- + GSeekType type,
- + GError **err)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- + int whence;
- + off_t tmp_offset;
- + off_t result;
- +
- + switch (type)
- + {
- + case G_SEEK_SET:
- + whence = SEEK_SET;
- + break;
- + case G_SEEK_CUR:
- + whence = SEEK_CUR;
- + break;
- + case G_SEEK_END:
- + whence = SEEK_END;
- + break;
- + default:
- + whence = -1; /* Shut the compiler up */
- + g_assert_not_reached ();
- + }
- +
- + tmp_offset = offset;
- + if (tmp_offset != offset)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (EINVAL),
- + g_strerror (EINVAL));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + result = lseek (unix_channel->fd, tmp_offset, whence);
- +
- + if (result < 0)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +
- +static GIOStatus
- +g_io_unix_close (GIOChannel *channel,
- + GError **err)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- +
- + if (close (unix_channel->fd) < 0)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static void
- +g_io_unix_free (GIOChannel *channel)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- +
- + g_free (unix_channel);
- +}
- +
- +static GSource *
- +g_io_unix_create_watch (GIOChannel *channel,
- + GIOCondition condition)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- + GSource *source;
- + GIOUnixWatch *watch;
- +
- +
- + source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
- + watch = (GIOUnixWatch *)source;
- +
- + watch->channel = channel;
- + g_io_channel_ref (channel);
- +
- + watch->condition = condition;
- +
- + watch->pollfd.fd = unix_channel->fd;
- + watch->pollfd.events = condition;
- +
- + g_source_add_poll (source, &watch->pollfd);
- +
- + return source;
- +}
- +
- +static GIOStatus
- +g_io_unix_set_flags (GIOChannel *channel,
- + GIOFlags flags,
- + GError **err)
- +{
- + glong fcntl_flags;
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
- +
- + fcntl_flags = 0;
- +
- + if (flags & G_IO_FLAG_APPEND)
- + fcntl_flags |= O_APPEND;
- + if (flags & G_IO_FLAG_NONBLOCK)
- +#ifdef O_NONBLOCK
- + fcntl_flags |= O_NONBLOCK;
- +#else
- + fcntl_flags |= O_NDELAY;
- +#endif
- +
- + if (fcntl (unix_channel->fd, F_SETFL, fcntl_flags) == -1)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_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;
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *) channel;
- +
- + 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 (fcntl_flags & O_APPEND)
- + flags |= G_IO_FLAG_APPEND;
- +#ifdef O_NONBLOCK
- + if (fcntl_flags & O_NONBLOCK)
- +#else
- + if (fcntl_flags & O_NDELAY)
- +#endif
- + flags |= G_IO_FLAG_NONBLOCK;
- +
- + switch (fcntl_flags & (O_RDONLY | O_WRONLY | O_RDWR))
- + {
- + case O_RDONLY:
- + channel->is_readable = TRUE;
- + channel->is_writeable = FALSE;
- + break;
- + case O_WRONLY:
- + channel->is_readable = FALSE;
- + channel->is_writeable = TRUE;
- + break;
- + case O_RDWR:
- + channel->is_readable = TRUE;
- + channel->is_writeable = TRUE;
- + break;
- + default:
- + g_assert_not_reached ();
- + }
- +
- + return flags;
- +}
- +
- +GIOChannel *
- +g_io_channel_new_file (const gchar *filename,
- + const gchar *mode,
- + GError **error)
- +{
- + int fid, flags;
- + mode_t create_mode;
- + GIOChannel *channel;
- + enum { /* Cheesy hack */
- + MODE_R = 1 << 0,
- + MODE_W = 1 << 1,
- + MODE_A = 1 << 2,
- + MODE_PLUS = 1 << 3
- + } mode_num;
- + struct stat buffer;
- +
- + g_return_val_if_fail (filename != NULL, NULL);
- + g_return_val_if_fail (mode != NULL, NULL);
- + g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
- +
- + switch (mode[0])
- + {
- + case 'r':
- + mode_num = MODE_R;
- + break;
- + case 'w':
- + mode_num = MODE_W;
- + break;
- + case 'a':
- + mode_num = MODE_A;
- + break;
- + default:
- + g_warning ("Invalid GIOFileMode %s.\n", mode);
- + return NULL;
- + }
- +
- + switch (mode[1])
- + {
- + case '\0':
- + break;
- + case '+':
- + if (mode[2] == '\0')
- + {
- + mode_num |= MODE_PLUS;
- + break;
- + }
- + /* Fall through */
- + default:
- + g_warning ("Invalid GIOFileMode %s.\n", mode);
- + return NULL;
- + }
- +
- + switch (mode_num)
- + {
- + case MODE_R:
- + flags = O_RDONLY;
- + break;
- + case MODE_W:
- + flags = O_WRONLY | O_TRUNC | O_CREAT;
- + break;
- + case MODE_A:
- + flags = O_WRONLY | O_APPEND | O_CREAT;
- + break;
- + case MODE_R | MODE_PLUS:
- + flags = O_RDWR;
- + break;
- + case MODE_W | MODE_PLUS:
- + flags = O_RDWR | O_TRUNC | O_CREAT;
- + break;
- + case MODE_A | MODE_PLUS:
- + flags = O_RDWR | O_APPEND | O_CREAT;
- + break;
- + default:
- + g_assert_not_reached ();
- + flags = 0;
- + }
- +
- + create_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- + fid = open (filename, flags, create_mode);
- + if (fid == -1)
- + {
- + g_set_error (error, G_FILE_ERROR,
- + g_file_error_from_errno (errno),
- + g_strerror (errno));
- + return (GIOChannel *)NULL;
- + }
- +
- + if (fstat (fid, &buffer) == -1) /* In case someone opens a FIFO */
- + {
- + close (fid);
- + g_set_error (error, G_FILE_ERROR,
- + g_file_error_from_errno (errno),
- + g_strerror (errno));
- + return (GIOChannel *)NULL;
- + }
- +
- + channel = (GIOChannel *) g_new (GIOUnixChannel, 1);
- +
- + channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
- + || S_ISBLK (buffer.st_mode);
- +
- + switch (mode_num)
- + {
- + case MODE_R:
- + channel->is_readable = TRUE;
- + channel->is_writeable = FALSE;
- + break;
- + case MODE_W:
- + case MODE_A:
- + channel->is_readable = FALSE;
- + channel->is_writeable = TRUE;
- + break;
- + case MODE_R | MODE_PLUS:
- + case MODE_W | MODE_PLUS:
- + case MODE_A | MODE_PLUS:
- + channel->is_readable = TRUE;
- + channel->is_writeable = TRUE;
- + break;
- + default:
- + g_assert_not_reached ();
- + }
- +
- + g_io_channel_init (channel);
- + channel->close_on_unref = TRUE; /* must be after g_io_channel_init () */
- + channel->funcs = &unix_channel_funcs;
- +
- + ((GIOUnixChannel *) channel)->fd = fid;
- + return channel;
- +}
- +
- +GIOChannel *
- +g_io_channel_unix_new (gint fd)
- +{
- + struct stat buffer;
- + GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
- + GIOChannel *channel = (GIOChannel *)unix_channel;
- +
- + g_io_channel_init (channel);
- + channel->funcs = &unix_channel_funcs;
- +
- + unix_channel->fd = fd;
- +
- + /* I'm not sure if fstat on a non-file (e.g., socket) works
- + * it should be safe to say if it fails, the fd isn't seekable.
- + */
- + /* Newer UNIX versions support S_ISSOCK(), fstat() will probably
- + * succeed in most cases.
- + */
- + if (fstat (unix_channel->fd, &buffer) == 0)
- + channel->is_seekable = S_ISREG (buffer.st_mode) || S_ISCHR (buffer.st_mode)
- + || S_ISBLK (buffer.st_mode);
- + else /* Assume not seekable */
- + channel->is_seekable = FALSE;
- +
- + g_io_unix_get_flags (channel); /* Sets is_readable, is_writeable */
- +
- + return channel;
- +}
- +
- +gint
- +g_io_channel_unix_get_fd (GIOChannel *channel)
- +{
- + GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
- + return unix_channel->fd;
- +}
- diff --git a/clients/Instantbird/giowin32.c b/clients/Instantbird/giowin32.c
- new file mode 100755
- index 0000000..83cb86c
- --- /dev/null
- +++ b/clients/Instantbird/giowin32.c
- @@ -0,0 +1,2129 @@
- +/* GLIB - Library of useful routines for C programming
- + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- + *
- + * giowin32.c: IO Channels for Win32.
- + * Copyright 1998 Owen Taylor and Tor Lillqvist
- + * Copyright 1999-2000 Tor Lillqvist and Craig Setera
- + * Copyright 2001-2003 Andrew Lanoix
- + *
- + * This library is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU Lesser General Public
- + * License as published by the Free Software Foundation; either
- + * version 2 of the License, or (at your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- + * Lesser General Public License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public
- + * License along with this library; if not, write to the
- + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- + * Boston, MA 02111-1307, USA.
- + */
- +
- +/*
- + * Modified by the GLib Team and others 1997-2000. See the AUTHORS
- + * file for a list of people on the GLib Team. See the ChangeLog
- + * files for a list of changes. These files are distributed with
- + * GLib at ftp://ftp.gtk.org/pub/gtk/.
- + */
- +
- +#include "config.h"
- +
- +#include "glib.h"
- +
- +#include <stdlib.h>
- +#include <winsock2.h>
- +#include <windows.h>
- +#include <conio.h>
- +#include <fcntl.h>
- +#include <io.h>
- +#include <process.h>
- +#include <errno.h>
- +#include <sys/stat.h>
- +
- +#include "gstdio.h"
- +#include "glibintl.h"
- +
- +#include "galias.h"
- +
- +typedef struct _GIOWin32Channel GIOWin32Channel;
- +typedef struct _GIOWin32Watch GIOWin32Watch;
- +
- +#define BUFFER_SIZE 4096
- +
- +typedef enum {
- + G_IO_WIN32_WINDOWS_MESSAGES, /* Windows messages */
- + G_IO_WIN32_FILE_DESC, /* Unix-like file descriptors from
- + * _open() or _pipe(), except for console IO.
- + * Have to create separate thread to read.
- + */
- + G_IO_WIN32_CONSOLE, /* Console IO (usually stdin, stdout, stderr) */
- + G_IO_WIN32_SOCKET /* Sockets. No separate thread */
- +} GIOWin32ChannelType;
- +
- +struct _GIOWin32Channel {
- + GIOChannel channel;
- + gint fd; /* Either a Unix-like file handle as provided
- + * by the Microsoft C runtime, or a SOCKET
- + * as provided by WinSock.
- + */
- + GIOWin32ChannelType type;
- +
- + gboolean debug;
- +
- + /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
- + HWND hwnd; /* handle of window, or NULL */
- +
- + /* Following fields are used by fd channels. */
- + CRITICAL_SECTION mutex;
- +
- + int direction; /* 0 means we read from it,
- + * 1 means we write to it.
- + */
- +
- + gboolean running; /* Is reader thread running. FALSE if
- + * EOF has been reached.
- + */
- + gboolean needs_close; /* If the channel has been closed while
- + * the reader thread was still running.
- + */
- + guint thread_id; /* If non-NULL has a reader thread, or has
- + * had.*/
- + HANDLE data_avail_event;
- +
- + gushort revents;
- +
- + /* Following fields used by fd channels for input */
- +
- + /* Data is kept in a circular buffer. To be able to distinguish between
- + * empty and full buffer, we cannot fill it completely, but have to
- + * leave a one character gap.
- + *
- + * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
- + *
- + * Empty: wrp == rdp
- + * Full: (wrp + 1) % BUFFER_SIZE == rdp
- + * Partial: otherwise
- + */
- + guchar *buffer; /* (Circular) buffer */
- + gint wrp, rdp; /* Buffer indices for writing and reading */
- + HANDLE space_avail_event;
- +
- + /* Following fields used by socket channels */
- + int event_mask;
- + int last_events;
- + int event;
- + gboolean write_would_have_blocked;
- +};
- +
- +#define LOCK(mutex) EnterCriticalSection (&mutex)
- +#define UNLOCK(mutex) LeaveCriticalSection (&mutex)
- +
- +struct _GIOWin32Watch {
- + GSource source;
- + GPollFD pollfd;
- + GIOChannel *channel;
- + GIOCondition condition;
- +};
- +
- +static void
- +g_win32_print_access_mode (int flags)
- +{
- + g_print ("%s%s%s%s%s%s%s%s%s%s",
- + ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
- + ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
- + ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
- + (flags & _O_APPEND ? "|O_APPEND" : ""),
- + (flags & _O_RANDOM ? "|O_RANDOM" : ""),
- + (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
- + (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
- + (flags & _O_CREAT ? "|O_CREAT" : ""),
- + (flags & _O_TRUNC ? "|O_TRUNC" : ""),
- + (flags & _O_EXCL ? "|O_EXCL" : ""),
- + (flags & _O_TEXT ? "|O_TEXT" : ""),
- + (flags & _O_BINARY ? "|O_BINARY" : ""));
- +}
- +
- +static void
- +g_win32_print_gioflags (GIOFlags flags)
- +{
- + char *bar = "";
- +
- + if (flags & G_IO_FLAG_APPEND)
- + bar = "|", g_print ("APPEND");
- + if (flags & G_IO_FLAG_NONBLOCK)
- + g_print ("%sNONBLOCK", bar), bar = "|";
- + if (flags & G_IO_FLAG_IS_READABLE)
- + g_print ("%sREADABLE", bar), bar = "|";
- + if (flags & G_IO_FLAG_IS_WRITEABLE)
- + g_print ("%sWRITEABLE", bar), bar = "|";
- + if (flags & G_IO_FLAG_IS_SEEKABLE)
- + g_print ("%sSEEKABLE", bar), bar = "|";
- +}
- +
- +static const char *
- +event_mask_to_string (int mask)
- +{
- + char buf[100];
- + int checked_bits = 0;
- + char *bufp = buf;
- +
- + if (mask == 0)
- + return "";
- +
- +#define BIT(n) checked_bits |= FD_##n; if (mask & FD_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : ""))
- +
- + BIT (READ);
- + BIT (WRITE);
- + BIT (OOB);
- + BIT (ACCEPT);
- + BIT (CONNECT);
- + BIT (CLOSE);
- + BIT (QOS);
- + BIT (GROUP_QOS);
- + BIT (ROUTING_INTERFACE_CHANGE);
- + BIT (ADDRESS_LIST_CHANGE);
- +
- +#undef BIT
- +
- + if ((mask & ~checked_bits) != 0)
- + bufp += sprintf (bufp, "|%#x", mask & ~checked_bits);
- +
- + return g_quark_to_string (g_quark_from_string (buf));
- +}
- +
- +static const char *
- +condition_to_string (GIOCondition condition)
- +{
- + char buf[100];
- + int checked_bits = 0;
- + char *bufp = buf;
- +
- + if (condition == 0)
- + return "";
- +
- +#define BIT(n) checked_bits |= G_IO_##n; if (condition & G_IO_##n) bufp += sprintf (bufp, "%s" #n, (bufp>buf ? "|" : ""))
- +
- + BIT (IN);
- + BIT (OUT);
- + BIT (PRI);
- + BIT (ERR);
- + BIT (HUP);
- + BIT (NVAL);
- +
- +#undef BIT
- +
- + if ((condition & ~checked_bits) != 0)
- + bufp += sprintf (bufp, "|%#x", condition & ~checked_bits);
- +
- + return g_quark_to_string (g_quark_from_string (buf));
- +}
- +
- +static gboolean
- +g_io_win32_get_debug_flag (void)
- +{
- + return (getenv ("G_IO_WIN32_DEBUG") != NULL);
- +}
- +
- +static char *
- +winsock_error_message (int number)
- +{
- + static char unk[100];
- +
- + switch (number) {
- + case WSAEINTR:
- + return "Interrupted function call";
- + case WSAEACCES:
- + return "Permission denied";
- + case WSAEFAULT:
- + return "Bad address";
- + case WSAEINVAL:
- + return "Invalid argument";
- + case WSAEMFILE:
- + return "Too many open sockets";
- + case WSAEWOULDBLOCK:
- + return "Resource temporarily unavailable";
- + case WSAEINPROGRESS:
- + return "Operation now in progress";
- + case WSAEALREADY:
- + return "Operation already in progress";
- + case WSAENOTSOCK:
- + return "Socket operation on nonsocket";
- + case WSAEDESTADDRREQ:
- + return "Destination address required";
- + case WSAEMSGSIZE:
- + return "Message too long";
- + case WSAEPROTOTYPE:
- + return "Protocol wrong type for socket";
- + case WSAENOPROTOOPT:
- + return "Bad protocol option";
- + case WSAEPROTONOSUPPORT:
- + return "Protocol not supported";
- + case WSAESOCKTNOSUPPORT:
- + return "Socket type not supported";
- + case WSAEOPNOTSUPP:
- + return "Operation not supported on transport endpoint";
- + case WSAEPFNOSUPPORT:
- + return "Protocol family not supported";
- + case WSAEAFNOSUPPORT:
- + return "Address family not supported by protocol family";
- + case WSAEADDRINUSE:
- + return "Address already in use";
- + case WSAEADDRNOTAVAIL:
- + return "Address not available";
- + case WSAENETDOWN:
- + return "Network interface is not configured";
- + case WSAENETUNREACH:
- + return "Network is unreachable";
- + case WSAENETRESET:
- + return "Network dropped connection on reset";
- + case WSAECONNABORTED:
- + return "Software caused connection abort";
- + case WSAECONNRESET:
- + return "Connection reset by peer";
- + case WSAENOBUFS:
- + return "No buffer space available";
- + case WSAEISCONN:
- + return "Socket is already connected";
- + case WSAENOTCONN:
- + return "Socket is not connected";
- + case WSAESHUTDOWN:
- + return "Can't send after socket shutdown";
- + case WSAETIMEDOUT:
- + return "Connection timed out";
- + case WSAECONNREFUSED:
- + return "Connection refused";
- + case WSAEHOSTDOWN:
- + return "Host is down";
- + case WSAEHOSTUNREACH:
- + return "Host is unreachable";
- + case WSAEPROCLIM:
- + return "Too many processes";
- + case WSASYSNOTREADY:
- + return "Network subsystem is unavailable";
- + case WSAVERNOTSUPPORTED:
- + return "Winsock.dll version out of range";
- + case WSANOTINITIALISED:
- + return "Successful WSAStartup not yet performed";
- + case WSAEDISCON:
- + return "Graceful shutdown in progress";
- + case WSATYPE_NOT_FOUND:
- + return "Class type not found";
- + case WSAHOST_NOT_FOUND:
- + return "Host not found";
- + case WSATRY_AGAIN:
- + return "Nonauthoritative host not found";
- + case WSANO_RECOVERY:
- + return "This is a nonrecoverable error";
- + case WSANO_DATA:
- + return "Valid name, no data record of requested type";
- + case WSA_INVALID_HANDLE:
- + return "Specified event object handle is invalid";
- + case WSA_INVALID_PARAMETER:
- + return "One or more parameters are invalid";
- + case WSA_IO_INCOMPLETE:
- + return "Overlapped I/O event object not in signaled state";
- + case WSA_NOT_ENOUGH_MEMORY:
- + return "Insufficient memory available";
- + case WSA_OPERATION_ABORTED:
- + return "Overlapped operation aborted";
- + case WSAEINVALIDPROCTABLE:
- + return "Invalid procedure table from service provider";
- + case WSAEINVALIDPROVIDER:
- + return "Invalid service provider version number";
- + case WSAEPROVIDERFAILEDINIT:
- + return "Unable to initialize a service provider";
- + case WSASYSCALLFAILURE:
- + return "System call failure";
- + default:
- + sprintf (unk, "Unknown WinSock error %d", number);
- + return unk;
- + }
- +}
- +
- +static void
- +g_io_channel_win32_init (GIOWin32Channel *channel)
- +{
- + channel->debug = g_io_win32_get_debug_flag ();
- + channel->buffer = NULL;
- + channel->running = FALSE;
- + channel->needs_close = FALSE;
- + channel->thread_id = 0;
- + channel->data_avail_event = NULL;
- + channel->revents = 0;
- + channel->space_avail_event = NULL;
- + channel->event_mask = 0;
- + channel->last_events = 0;
- + channel->event = 0;
- + channel->write_would_have_blocked = FALSE;
- + InitializeCriticalSection (&channel->mutex);
- +}
- +
- +static void
- +create_events (GIOWin32Channel *channel)
- +{
- + SECURITY_ATTRIBUTES sec_attrs;
- +
- + sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
- + sec_attrs.lpSecurityDescriptor = NULL;
- + sec_attrs.bInheritHandle = FALSE;
- +
- + /* The data available event is manual reset, the space available event
- + * is automatic reset.
- + */
- + if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
- + || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
- + {
- + gchar *emsg = g_win32_error_message (GetLastError ());
- + g_error ("Error creating event: %s", emsg);
- + g_free (emsg);
- + }
- +}
- +
- +static unsigned __stdcall
- +read_thread (void *parameter)
- +{
- + GIOWin32Channel *channel = parameter;
- + guchar *buffer;
- + guint nbytes;
- +
- + g_io_channel_ref ((GIOChannel *)channel);
- +
- + if (channel->debug)
- + g_print ("read_thread %#x: start fd=%d, data_avail=%#x space_avail=%#x\n",
- + channel->thread_id,
- + channel->fd,
- + (guint) channel->data_avail_event,
- + (guint) channel->space_avail_event);
- +
- + channel->direction = 0;
- + channel->buffer = g_malloc (BUFFER_SIZE);
- + channel->rdp = channel->wrp = 0;
- + channel->running = TRUE;
- +
- + SetEvent (channel->space_avail_event);
- +
- + LOCK (channel->mutex);
- + while (channel->running)
- + {
- + if (channel->debug)
- + g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
- + {
- + /* Buffer is full */
- + if (channel->debug)
- + g_print ("read_thread %#x: resetting space_avail\n",
- + channel->thread_id);
- + ResetEvent (channel->space_avail_event);
- + if (channel->debug)
- + g_print ("read_thread %#x: waiting for space\n",
- + channel->thread_id);
- + UNLOCK (channel->mutex);
- + WaitForSingleObject (channel->space_avail_event, INFINITE);
- + LOCK (channel->mutex);
- + if (channel->debug)
- + g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + }
- +
- + buffer = channel->buffer + channel->wrp;
- +
- + /* Always leave at least one byte unused gap to be able to
- + * distinguish between the full and empty condition...
- + */
- + nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
- + BUFFER_SIZE - channel->wrp);
- +
- + if (channel->debug)
- + g_print ("read_thread %#x: calling read() for %d bytes\n",
- + channel->thread_id, nbytes);
- +
- + UNLOCK (channel->mutex);
- +
- + nbytes = read (channel->fd, buffer, nbytes);
- +
- + LOCK (channel->mutex);
- +
- + channel->revents = G_IO_IN;
- + if (nbytes == 0)
- + channel->revents |= G_IO_HUP;
- + else if (nbytes < 0)
- + channel->revents |= G_IO_ERR;
- +
- + if (channel->debug)
- + g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
- + channel->thread_id, nbytes, channel->rdp, channel->wrp);
- +
- + if (nbytes <= 0)
- + break;
- +
- + channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
- + if (channel->debug)
- + g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + SetEvent (channel->data_avail_event);
- + }
- +
- + channel->running = FALSE;
- + if (channel->needs_close)
- + {
- + if (channel->debug)
- + g_print ("read_thread %#x: channel fd %d needs closing\n",
- + channel->thread_id, channel->fd);
- + close (channel->fd);
- + channel->fd = -1;
- + }
- +
- + if (channel->debug)
- + g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + SetEvent (channel->data_avail_event);
- + UNLOCK (channel->mutex);
- +
- + g_io_channel_unref ((GIOChannel *)channel);
- +
- + /* No need to call _endthreadex(), the actual thread starter routine
- + * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
- + * _endthreadex() for us.
- + */
- +
- + return 0;
- +}
- +
- +static unsigned __stdcall
- +write_thread (void *parameter)
- +{
- + GIOWin32Channel *channel = parameter;
- + guchar *buffer;
- + guint nbytes;
- +
- + g_io_channel_ref ((GIOChannel *)channel);
- +
- + if (channel->debug)
- + g_print ("write_thread %#x: start fd=%d, data_avail=%#x space_avail=%#x\n",
- + channel->thread_id,
- + channel->fd,
- + (guint) channel->data_avail_event,
- + (guint) channel->space_avail_event);
- +
- + channel->direction = 1;
- + channel->buffer = g_malloc (BUFFER_SIZE);
- + channel->rdp = channel->wrp = 0;
- + channel->running = TRUE;
- +
- + SetEvent (channel->space_avail_event);
- +
- + /* We use the same event objects as for a reader thread, but with
- + * reversed meaning. So, space_avail is used if data is available
- + * for writing, and data_avail is used if space is available in the
- + * write buffer.
- + */
- +
- + LOCK (channel->mutex);
- + while (channel->running || channel->rdp != channel->wrp)
- + {
- + if (channel->debug)
- + g_print ("write_thread %#x: rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + if (channel->wrp == channel->rdp)
- + {
- + /* Buffer is empty. */
- + if (channel->debug)
- + g_print ("write_thread %#x: resetting space_avail\n",
- + channel->thread_id);
- + ResetEvent (channel->space_avail_event);
- + if (channel->debug)
- + g_print ("write_thread %#x: waiting for data\n",
- + channel->thread_id);
- + channel->revents = G_IO_OUT;
- + SetEvent (channel->data_avail_event);
- + UNLOCK (channel->mutex);
- + WaitForSingleObject (channel->space_avail_event, INFINITE);
- +
- + LOCK (channel->mutex);
- + if (channel->rdp == channel->wrp)
- + break;
- +
- + if (channel->debug)
- + g_print ("write_thread %#x: rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + }
- +
- + buffer = channel->buffer + channel->rdp;
- + if (channel->rdp < channel->wrp)
- + nbytes = channel->wrp - channel->rdp;
- + else
- + nbytes = BUFFER_SIZE - channel->rdp;
- +
- + if (channel->debug)
- + g_print ("write_thread %#x: calling write() for %d bytes\n",
- + channel->thread_id, nbytes);
- +
- + UNLOCK (channel->mutex);
- + nbytes = write (channel->fd, buffer, nbytes);
- + LOCK (channel->mutex);
- +
- + if (channel->debug)
- + g_print ("write_thread %#x: write(%i) returned %d, rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->fd, nbytes, channel->rdp, channel->wrp);
- +
- + channel->revents = 0;
- + if (nbytes > 0)
- + channel->revents |= G_IO_OUT;
- + else if (nbytes <= 0)
- + channel->revents |= G_IO_ERR;
- +
- + channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
- +
- + if (nbytes <= 0)
- + break;
- +
- + if (channel->debug)
- + g_print ("write_thread: setting data_avail for thread %#x\n",
- + channel->thread_id);
- + SetEvent (channel->data_avail_event);
- + }
- +
- + channel->running = FALSE;
- + if (channel->needs_close)
- + {
- + if (channel->debug)
- + g_print ("write_thread %#x: channel fd %d needs closing\n",
- + channel->thread_id, channel->fd);
- + close (channel->fd);
- + channel->fd = -1;
- + }
- +
- + UNLOCK (channel->mutex);
- +
- + g_io_channel_unref ((GIOChannel *)channel);
- +
- + return 0;
- +}
- +
- +static void
- +create_thread (GIOWin32Channel *channel,
- + GIOCondition condition,
- + unsigned (__stdcall *thread) (void *parameter))
- +{
- + HANDLE thread_handle;
- +
- + thread_handle = (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
- + &channel->thread_id);
- + if (thread_handle == 0)
- + g_warning (G_STRLOC ": Error creating reader thread: %s",
- + g_strerror (errno));
- + else if (!CloseHandle (thread_handle))
- + g_warning (G_STRLOC ": Error closing thread handle: %s\n",
- + g_win32_error_message (GetLastError ()));
- +
- + WaitForSingleObject (channel->space_avail_event, INFINITE);
- +}
- +
- +static GIOStatus
- +buffer_read (GIOWin32Channel *channel,
- + guchar *dest,
- + gsize count,
- + gsize *bytes_read,
- + GError **err)
- +{
- + guint nbytes;
- + guint left = count;
- +
- + LOCK (channel->mutex);
- + if (channel->debug)
- + g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
- + channel->thread_id, count, channel->rdp, channel->wrp);
- +
- + if (channel->wrp == channel->rdp)
- + {
- + UNLOCK (channel->mutex);
- + if (channel->debug)
- + g_print ("waiting for data from thread %#x\n", channel->thread_id);
- + WaitForSingleObject (channel->data_avail_event, INFINITE);
- + if (channel->debug)
- + g_print ("done waiting for data from thread %#x\n", channel->thread_id);
- + LOCK (channel->mutex);
- + if (channel->wrp == channel->rdp && !channel->running)
- + {
- + if (channel->debug)
- + g_print ("wrp==rdp, !running\n");
- + UNLOCK (channel->mutex);
- + *bytes_read = 0;
- + return G_IO_STATUS_EOF;
- + }
- + }
- +
- + if (channel->rdp < channel->wrp)
- + nbytes = channel->wrp - channel->rdp;
- + else
- + nbytes = BUFFER_SIZE - channel->rdp;
- + UNLOCK (channel->mutex);
- + nbytes = MIN (left, nbytes);
- + if (channel->debug)
- + g_print ("moving %d bytes from thread %#x\n",
- + nbytes, channel->thread_id);
- + memcpy (dest, channel->buffer + channel->rdp, nbytes);
- + dest += nbytes;
- + left -= nbytes;
- + LOCK (channel->mutex);
- + channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
- + if (channel->debug)
- + g_print ("setting space_avail for thread %#x\n", channel->thread_id);
- + SetEvent (channel->space_avail_event);
- + if (channel->debug)
- + g_print ("for thread %#x: rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + if (channel->running && channel->wrp == channel->rdp)
- + {
- + if (channel->debug)
- + g_print ("resetting data_avail of thread %#x\n",
- + channel->thread_id);
- + ResetEvent (channel->data_avail_event);
- + };
- + UNLOCK (channel->mutex);
- +
- + /* We have no way to indicate any errors form the actual
- + * read() or recv() call in the reader thread. Should we have?
- + */
- + *bytes_read = count - left;
- + return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
- +}
- +
- +
- +static GIOStatus
- +buffer_write (GIOWin32Channel *channel,
- + const guchar *dest,
- + gsize count,
- + gsize *bytes_written,
- + GError **err)
- +{
- + guint nbytes;
- + guint left = count;
- +
- + LOCK (channel->mutex);
- + if (channel->debug)
- + g_print ("buffer_write: writing to thread %#x %d bytes, rdp=%d, wrp=%d\n",
- + channel->thread_id, count, channel->rdp, channel->wrp);
- +
- + if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
- + {
- + /* Buffer is full */
- + if (channel->debug)
- + g_print ("buffer_write: tid %#x: resetting data_avail\n",
- + channel->thread_id);
- + ResetEvent (channel->data_avail_event);
- + if (channel->debug)
- + g_print ("buffer_write: tid %#x: waiting for space\n",
- + channel->thread_id);
- + UNLOCK (channel->mutex);
- + WaitForSingleObject (channel->data_avail_event, INFINITE);
- + LOCK (channel->mutex);
- + if (channel->debug)
- + g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + }
- +
- + nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
- + BUFFER_SIZE - channel->wrp);
- +
- + UNLOCK (channel->mutex);
- + nbytes = MIN (left, nbytes);
- + if (channel->debug)
- + g_print ("buffer_write: tid %#x: writing %d bytes\n",
- + channel->thread_id, nbytes);
- + memcpy (channel->buffer + channel->wrp, dest, nbytes);
- + dest += nbytes;
- + left -= nbytes;
- + LOCK (channel->mutex);
- +
- + channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
- + if (channel->debug)
- + g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d, setting space_avail\n",
- + channel->thread_id, channel->rdp, channel->wrp);
- + SetEvent (channel->space_avail_event);
- +
- + if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
- + {
- + /* Buffer is full */
- + if (channel->debug)
- + g_print ("buffer_write: tid %#x: resetting data_avail\n",
- + channel->thread_id);
- + ResetEvent (channel->data_avail_event);
- + }
- +
- + UNLOCK (channel->mutex);
- +
- + /* We have no way to indicate any errors form the actual
- + * write() call in the writer thread. Should we have?
- + */
- + *bytes_written = count - left;
- + return (*bytes_written > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
- +}
- +
- +
- +static gboolean
- +g_io_win32_prepare (GSource *source,
- + gint *timeout)
- +{
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
- + GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
- + int event_mask;
- +
- + *timeout = -1;
- +
- + switch (channel->type)
- + {
- + case G_IO_WIN32_WINDOWS_MESSAGES:
- + case G_IO_WIN32_CONSOLE:
- + break;
- +
- + case G_IO_WIN32_FILE_DESC:
- + if (channel->debug)
- + g_print ("g_io_win32_prepare: for thread %#x buffer_condition:{%s}\n"
- + " watch->pollfd.events:{%s} watch->pollfd.revents:{%s} channel->revents:{%s}\n",
- + channel->thread_id, condition_to_string (buffer_condition),
- + condition_to_string (watch->pollfd.events),
- + condition_to_string (watch->pollfd.revents),
- + condition_to_string (channel->revents));
- +
- + LOCK (channel->mutex);
- + if (channel->running)
- + {
- + if (channel->direction == 0 && channel->wrp == channel->rdp)
- + {
- + if (channel->debug)
- + g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
- + channel->thread_id);
- + channel->revents = 0;
- + }
- + }
- + else
- + {
- + if (channel->direction == 1
- + && (channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
- + {
- + if (channel->debug)
- + g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = %i\n",
- + channel->thread_id, 0);
- + channel->revents = 0;
- + }
- + }
- + UNLOCK (channel->mutex);
- + break;
- +
- + case G_IO_WIN32_SOCKET:
- + event_mask = 0;
- + if (watch->condition & G_IO_IN)
- + event_mask |= (FD_READ | FD_ACCEPT);
- + if (watch->condition & G_IO_OUT)
- + event_mask |= (FD_WRITE | FD_CONNECT);
- + event_mask |= FD_CLOSE;
- +
- + if (channel->event_mask != event_mask /* || channel->event != watch->pollfd.fd*/)
- + {
- + if (channel->debug)
- + g_print ("g_io_win32_prepare: WSAEventSelect(%d, %#x, {%s}\n",
- + channel->fd, watch->pollfd.fd,
- + event_mask_to_string (event_mask));
- + if (WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd,
- + event_mask) == SOCKET_ERROR)
- + ; /* What? */
- + channel->event_mask = event_mask;
- +#if 0
- + channel->event = watch->pollfd.fd;
- +#endif
- + channel->last_events = 0;
- + }
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + abort ();
- + }
- + return ((watch->condition & buffer_condition) == watch->condition);
- +}
- +
- +static gboolean
- +g_io_win32_check (GSource *source)
- +{
- + MSG msg;
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- + GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
- + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
- + WSANETWORKEVENTS events;
- +
- + switch (channel->type)
- + {
- + case G_IO_WIN32_WINDOWS_MESSAGES:
- + return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
- +
- + case G_IO_WIN32_FILE_DESC:
- + if (channel->debug)
- + g_print ("g_io_win32_check: for thread %#x buffer_condition=%s\n"
- + " watch->pollfd.events={%s} watch->pollfd.revents={%s} channel->revents={%s}\n",
- + channel->thread_id, condition_to_string (buffer_condition),
- + condition_to_string (watch->pollfd.events),
- + condition_to_string (watch->pollfd.revents),
- + condition_to_string (channel->revents));
- +
- + watch->pollfd.revents = (watch->pollfd.events & channel->revents);
- +
- + return ((watch->pollfd.revents | buffer_condition) & watch->condition);
- +
- + case G_IO_WIN32_CONSOLE:
- + if (watch->channel->is_writeable)
- + return TRUE;
- + else if (watch->channel->is_readable)
- + {
- + INPUT_RECORD buffer;
- + DWORD n;
- + if (PeekConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n) &&
- + n == 1)
- + {
- + /* _kbhit() does quite complex processing to find out
- + * whether at least one of the key events pending corresponds
- + * to a "real" character that can be read.
- + */
- + if (_kbhit ())
- + return TRUE;
- +
- + /* Discard all other kinds of events */
- + ReadConsoleInput ((HANDLE) watch->pollfd.fd, &buffer, 1, &n);
- + }
- + }
- + return FALSE;
- +
- + case G_IO_WIN32_SOCKET:
- + if (channel->last_events & FD_WRITE)
- + {
- + if (channel->debug)
- + g_print ("g_io_win32_check: sock=%d event=%#x last_events has FD_WRITE\n",
- + channel->fd, watch->pollfd.fd);
- + }
- + else
- + {
- + WSAEnumNetworkEvents (channel->fd, 0, &events);
- +
- + if (channel->debug)
- + g_print ("g_io_win32_check: WSAEnumNetworkEvents (%d, %#x) revents={%s} condition={%s} events={%s}\n",
- + channel->fd, watch->pollfd.fd,
- + condition_to_string (watch->pollfd.revents),
- + condition_to_string (watch->condition),
- + event_mask_to_string (events.lNetworkEvents));
- +
- + if (watch->pollfd.revents != 0 &&
- + events.lNetworkEvents == 0 &&
- + !(channel->event_mask & FD_WRITE))
- + {
- + channel->event_mask = 0;
- + if (channel->debug)
- + g_print ("g_io_win32_check: WSAEventSelect(%d, %#x, {})\n",
- + channel->fd, watch->pollfd.fd);
- + WSAEventSelect (channel->fd, (HANDLE) watch->pollfd.fd, 0);
- + if (channel->debug)
- + g_print ("g_io_win32_check: ResetEvent(%#x)\n",
- + watch->pollfd.fd);
- + ResetEvent ((HANDLE) watch->pollfd.fd);
- + }
- + channel->last_events = events.lNetworkEvents;
- + }
- + watch->pollfd.revents = 0;
- + if (channel->last_events & (FD_READ | FD_ACCEPT))
- + watch->pollfd.revents |= G_IO_IN;
- + if (channel->last_events & FD_WRITE)
- + watch->pollfd.revents |= G_IO_OUT;
- + else
- + {
- + /* We have called WSAEnumNetworkEvents() above but it didn't
- + * set FD_WRITE.
- + */
- + if (events.lNetworkEvents & FD_CONNECT)
- + {
- + if (events.iErrorCode[FD_CONNECT_BIT] == 0)
- + watch->pollfd.revents |= G_IO_OUT;
- + else
- + watch->pollfd.revents |= (G_IO_HUP | G_IO_ERR);
- + }
- + if (watch->pollfd.revents == 0 && (channel->last_events & (FD_CLOSE)))
- + watch->pollfd.revents |= G_IO_HUP;
- + }
- +
- + /* Regardless of WSAEnumNetworkEvents() result, if watching for
- + * writability, unless last write would have blocked set
- + * G_IO_OUT. But never set both G_IO_OUT and G_IO_HUP.
- + */
- + if (!(watch->pollfd.revents & G_IO_HUP) &&
- + !channel->write_would_have_blocked &&
- + (channel->event_mask & FD_WRITE))
- + watch->pollfd.revents |= G_IO_OUT;
- +
- + return ((watch->pollfd.revents | buffer_condition) & watch->condition);
- +
- + default:
- + g_assert_not_reached ();
- + abort ();
- + }
- +}
- +
- +static gboolean
- +g_io_win32_dispatch (GSource *source,
- + GSourceFunc callback,
- + gpointer user_data)
- +{
- + GIOFunc func = (GIOFunc)callback;
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- + GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
- + GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
- +
- + if (!func)
- + {
- + g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
- + "You must call g_source_connect().");
- + return FALSE;
- + }
- +
- + if (channel->debug)
- + g_print ("g_io_win32_dispatch: pollfd.revents=%s condition=%s result=%s\n",
- + condition_to_string (watch->pollfd.revents),
- + condition_to_string (watch->condition),
- + condition_to_string ((watch->pollfd.revents | buffer_condition) & watch->condition));
- +
- + return (*func) (watch->channel,
- + (watch->pollfd.revents | buffer_condition) & watch->condition,
- + user_data);
- +}
- +
- +static void
- +g_io_win32_finalize (GSource *source)
- +{
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- + GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
- +
- + switch (channel->type)
- + {
- + case G_IO_WIN32_WINDOWS_MESSAGES:
- + case G_IO_WIN32_CONSOLE:
- + break;
- +
- + case G_IO_WIN32_FILE_DESC:
- + LOCK (channel->mutex);
- + if (channel->debug)
- + g_print ("g_io_win32_finalize: channel with thread %#x\n",
- + channel->thread_id);
- + UNLOCK (channel->mutex);
- + break;
- +
- + case G_IO_WIN32_SOCKET:
- + if (channel->debug)
- + g_print ("g_io_win32_finalize: channel is for sock=%d\n", channel->fd);
- +#if 0
- + CloseHandle ((HANDLE) watch->pollfd.fd);
- + channel->event = 0;
- + channel->event_mask = 0;
- +#endif
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + abort ();
- + }
- + g_io_channel_unref (watch->channel);
- +}
- +
- +GSourceFuncs g_io_watch_funcs = {
- + g_io_win32_prepare,
- + g_io_win32_check,
- + g_io_win32_dispatch,
- + g_io_win32_finalize
- +};
- +
- +static GIOStatus
- +g_io_win32_msg_read (GIOChannel *channel,
- + gchar *buf,
- + gsize count,
- + gsize *bytes_read,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + MSG msg; /* In case of alignment problems */
- +
- + if (count < sizeof (MSG))
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
- + "Incorrect message size"); /* Informative enough error message? */
- + return G_IO_STATUS_ERROR;
- + }
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_msg_read: for %#x\n",
- + (guint) win32_channel->hwnd);
- + if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
- + return G_IO_STATUS_AGAIN;
- +
- + memmove (buf, &msg, sizeof (MSG));
- + *bytes_read = sizeof (MSG);
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +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))
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
- + "Incorrect message size"); /* Informative enough error message? */
- + 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))
- + {
- + gchar *emsg = g_win32_error_message (GetLastError ());
- + g_set_error (err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
- + g_free (emsg);
- + return G_IO_STATUS_ERROR;
- + }
- +
- + *bytes_written = sizeof (MSG);
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GIOStatus
- +g_io_win32_msg_close (GIOChannel *channel,
- + GError **err)
- +{
- + /* Nothing to be done. Or should we set hwnd to some invalid value? */
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static void
- +g_io_win32_free (GIOChannel *channel)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_free channel fd=%d\n", win32_channel->fd);
- +
- + if (win32_channel->data_avail_event)
- + CloseHandle (win32_channel->data_avail_event);
- + if (win32_channel->space_avail_event)
- + CloseHandle (win32_channel->space_avail_event);
- + if (win32_channel->type == G_IO_WIN32_SOCKET)
- + WSAEventSelect (win32_channel->fd, NULL, 0);
- + DeleteCriticalSection (&win32_channel->mutex);
- +
- + g_free (win32_channel->buffer);
- + g_free (win32_channel);
- +}
- +
- +static GSource *
- +g_io_win32_msg_create_watch (GIOChannel *channel,
- + GIOCondition condition)
- +{
- + GIOWin32Watch *watch;
- + GSource *source;
- +
- + source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
- + watch = (GIOWin32Watch *)source;
- +
- + watch->channel = channel;
- + g_io_channel_ref (channel);
- +
- + watch->condition = condition;
- +
- + watch->pollfd.fd = G_WIN32_MSG_HANDLE;
- + watch->pollfd.events = condition;
- +
- + g_source_add_poll (source, &watch->pollfd);
- +
- + return source;
- +}
- +
- +static GIOStatus
- +g_io_win32_fd_and_console_read (GIOChannel *channel,
- + gchar *buf,
- + gsize count,
- + gsize *bytes_read,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + gint result;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_fd_read: fd=%d count=%d\n",
- + win32_channel->fd, count);
- +
- + if (win32_channel->thread_id)
- + {
- + return buffer_read (win32_channel, buf, count, bytes_read, err);
- + }
- +
- + result = read (win32_channel->fd, buf, count);
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_fd_read: read() => %d\n", result);
- +
- + if (result < 0)
- + {
- + *bytes_read = 0;
- +
- + switch (errno)
- + {
- +#ifdef EAGAIN
- + case EAGAIN:
- + return G_IO_STATUS_AGAIN;
- +#endif
- + default:
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- +
- + *bytes_read = result;
- +
- + return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
- +}
- +
- +static GIOStatus
- +g_io_win32_fd_and_console_write (GIOChannel *channel,
- + const gchar *buf,
- + gsize count,
- + gsize *bytes_written,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + gint result;
- +
- + if (win32_channel->thread_id)
- + {
- + return buffer_write (win32_channel, buf, count, bytes_written, err);
- + }
- +
- + result = write (win32_channel->fd, buf, count);
- + 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)
- + {
- +#ifdef EAGAIN
- + case EAGAIN:
- + return G_IO_STATUS_AGAIN;
- +#endif
- + default:
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- +
- + *bytes_written = result;
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GIOStatus
- +g_io_win32_fd_seek (GIOChannel *channel,
- + gint64 offset,
- + GSeekType type,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + int whence;
- + off_t tmp_offset;
- + off_t result;
- +
- + switch (type)
- + {
- + case G_SEEK_SET:
- + whence = SEEK_SET;
- + break;
- + case G_SEEK_CUR:
- + whence = SEEK_CUR;
- + break;
- + case G_SEEK_END:
- + whence = SEEK_END;
- + break;
- + default:
- + whence = -1; /* Keep the compiler quiet */
- + g_assert_not_reached ();
- + abort ();
- + }
- +
- + tmp_offset = offset;
- + if (tmp_offset != offset)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (EINVAL),
- + g_strerror (EINVAL));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + result = lseek (win32_channel->fd, tmp_offset, whence);
- +
- + if (result < 0)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GIOStatus
- +g_io_win32_fd_close (GIOChannel *channel,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + if (win32_channel->debug)
- + g_print ("thread %#x: closing fd %d\n",
- + win32_channel->thread_id,
- + win32_channel->fd);
- + LOCK (win32_channel->mutex);
- + if (win32_channel->running)
- + {
- + if (win32_channel->debug)
- + g_print ("thread %#x: running, marking fd %d for later close\n",
- + win32_channel->thread_id, win32_channel->fd);
- + win32_channel->running = FALSE;
- + win32_channel->needs_close = TRUE;
- + if (win32_channel->direction == 0)
- + SetEvent (win32_channel->data_avail_event);
- + else
- + SetEvent (win32_channel->space_avail_event);
- + }
- + else
- + {
- + if (win32_channel->debug)
- + g_print ("closing fd %d\n", win32_channel->fd);
- + close (win32_channel->fd);
- + if (win32_channel->debug)
- + g_print ("closed fd %d, setting to -1\n",
- + win32_channel->fd);
- + win32_channel->fd = -1;
- + }
- + UNLOCK (win32_channel->mutex);
- +
- + /* FIXME error detection? */
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GSource *
- +g_io_win32_fd_create_watch (GIOChannel *channel,
- + GIOCondition condition)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- +
- + watch->channel = channel;
- + g_io_channel_ref (channel);
- +
- + watch->condition = condition;
- +
- + if (win32_channel->data_avail_event == NULL)
- + create_events (win32_channel);
- +
- + watch->pollfd.fd = (gint) win32_channel->data_avail_event;
- + watch->pollfd.events = condition;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_fd_create_watch: fd=%d condition={%s} handle=%#x\n",
- + win32_channel->fd, condition_to_string (condition), watch->pollfd.fd);
- +
- + LOCK (win32_channel->mutex);
- + if (win32_channel->thread_id == 0)
- + {
- + if (condition & G_IO_IN)
- + create_thread (win32_channel, condition, read_thread);
- + else if (condition & G_IO_OUT)
- + create_thread (win32_channel, condition, write_thread);
- + }
- +
- + g_source_add_poll (source, &watch->pollfd);
- + UNLOCK (win32_channel->mutex);
- +
- + return source;
- +}
- +
- +static GIOStatus
- +g_io_win32_console_close (GIOChannel *channel,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + if (close (win32_channel->fd) < 0)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + g_io_channel_error_from_errno (errno),
- + g_strerror (errno));
- + return G_IO_STATUS_ERROR;
- + }
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GSource *
- +g_io_win32_console_create_watch (GIOChannel *channel,
- + GIOCondition condition)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- +
- + watch->channel = channel;
- + g_io_channel_ref (channel);
- +
- + watch->condition = condition;
- +
- + watch->pollfd.fd = (gint) _get_osfhandle (win32_channel->fd);
- + watch->pollfd.events = condition;
- +
- + g_source_add_poll (source, &watch->pollfd);
- +
- + return source;
- +}
- +
- +static GIOStatus
- +g_io_win32_sock_read (GIOChannel *channel,
- + gchar *buf,
- + gsize count,
- + gsize *bytes_read,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + gint result;
- + GIOChannelError error;
- + int winsock_error;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_sock_read: sockfd=%d count=%d\n",
- + win32_channel->fd, count);
- +
- + result = recv (win32_channel->fd, buf, count, 0);
- + if (result == SOCKET_ERROR)
- + winsock_error = WSAGetLastError ();
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_sock_read: recv=%d %s\n",
- + result,
- + (result == SOCKET_ERROR ? winsock_error_message (winsock_error) : ""));
- +
- + if (result == SOCKET_ERROR)
- + {
- + *bytes_read = 0;
- +
- + switch (winsock_error)
- + {
- + case WSAEINVAL:
- + error = G_IO_CHANNEL_ERROR_INVAL;
- + break;
- + case WSAEWOULDBLOCK:
- + return G_IO_STATUS_AGAIN;
- + default:
- + error = G_IO_CHANNEL_ERROR_FAILED;
- + break;
- + }
- + g_set_error (err, G_IO_CHANNEL_ERROR, error,
- + winsock_error_message (winsock_error));
- + return G_IO_STATUS_ERROR;
- + }
- + else
- + {
- + *bytes_read = result;
- + if (result == 0)
- + return G_IO_STATUS_EOF;
- + else
- + return G_IO_STATUS_NORMAL;
- + }
- +}
- +
- +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;
- + int winsock_error;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_sock_write: sockfd=%d count=%d\n",
- + win32_channel->fd, count);
- +
- + result = send (win32_channel->fd, buf, count, 0);
- + if (result == SOCKET_ERROR)
- + winsock_error = WSAGetLastError ();
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_sock_write: send=%d %s\n",
- + result,
- + (result == SOCKET_ERROR ? winsock_error_message (winsock_error) : ""));
- +
- + if (result == SOCKET_ERROR)
- + {
- + *bytes_written = 0;
- +
- + switch (winsock_error)
- + {
- + case WSAEINVAL:
- + error = G_IO_CHANNEL_ERROR_INVAL;
- + break;
- + case WSAEWOULDBLOCK:
- + win32_channel->write_would_have_blocked = TRUE;
- + win32_channel->last_events = 0;
- + return G_IO_STATUS_AGAIN;
- + default:
- + error = G_IO_CHANNEL_ERROR_FAILED;
- + break;
- + }
- + g_set_error (err, G_IO_CHANNEL_ERROR, error,
- + winsock_error_message (winsock_error));
- +
- + return G_IO_STATUS_ERROR;
- + }
- + else
- + {
- + *bytes_written = result;
- + win32_channel->write_would_have_blocked = FALSE;
- +
- + return G_IO_STATUS_NORMAL;
- + }
- +}
- +
- +static GIOStatus
- +g_io_win32_sock_close (GIOChannel *channel,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + if (win32_channel->fd != -1)
- + {
- + if (win32_channel->debug)
- + g_print ("g_io_win32_sock_close: closing socket %d\n",
- + win32_channel->fd);
- +
- + closesocket (win32_channel->fd);
- + win32_channel->fd = -1;
- + }
- +
- + /* FIXME error detection? */
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GSource *
- +g_io_win32_sock_create_watch (GIOChannel *channel,
- + GIOCondition condition)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + GSource *source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
- + GIOWin32Watch *watch = (GIOWin32Watch *)source;
- +
- + watch->channel = channel;
- + g_io_channel_ref (channel);
- +
- + watch->condition = condition;
- +
- + if (win32_channel->event == 0)
- + win32_channel->event = (int) WSACreateEvent ();
- +
- + watch->pollfd.fd = win32_channel->event;
- + watch->pollfd.events = condition;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_win32_sock_create_watch: sock=%d handle=%#x condition={%s}\n",
- + win32_channel->fd, watch->pollfd.fd,
- + condition_to_string (watch->condition));
- +
- + g_source_add_poll (source, &watch->pollfd);
- +
- + return source;
- +}
- +
- +GIOChannel *
- +g_io_channel_new_file (const gchar *filename,
- + const gchar *mode,
- + GError **error)
- +{
- + int fid, flags, pmode;
- + GIOChannel *channel;
- +
- + enum { /* Cheesy hack */
- + MODE_R = 1 << 0,
- + MODE_W = 1 << 1,
- + MODE_A = 1 << 2,
- + MODE_PLUS = 1 << 3,
- + } mode_num;
- +
- + g_return_val_if_fail (filename != NULL, NULL);
- + g_return_val_if_fail (mode != NULL, NULL);
- + g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
- +
- + switch (mode[0])
- + {
- + case 'r':
- + mode_num = MODE_R;
- + break;
- + case 'w':
- + mode_num = MODE_W;
- + break;
- + case 'a':
- + mode_num = MODE_A;
- + break;
- + default:
- + g_warning ("Invalid GIOFileMode %s.\n", mode);
- + return NULL;
- + }
- +
- + switch (mode[1])
- + {
- + case '\0':
- + break;
- + case '+':
- + if (mode[2] == '\0')
- + {
- + mode_num |= MODE_PLUS;
- + break;
- + }
- + /* Fall through */
- + default:
- + g_warning ("Invalid GIOFileMode %s.\n", mode);
- + return NULL;
- + }
- +
- + switch (mode_num)
- + {
- + case MODE_R:
- + flags = O_RDONLY;
- + pmode = _S_IREAD;
- + break;
- + case MODE_W:
- + flags = O_WRONLY | O_TRUNC | O_CREAT;
- + pmode = _S_IWRITE;
- + break;
- + case MODE_A:
- + flags = O_WRONLY | O_APPEND | O_CREAT;
- + pmode = _S_IWRITE;
- + break;
- + case MODE_R | MODE_PLUS:
- + flags = O_RDWR;
- + pmode = _S_IREAD | _S_IWRITE;
- + break;
- + case MODE_W | MODE_PLUS:
- + flags = O_RDWR | O_TRUNC | O_CREAT;
- + pmode = _S_IREAD | _S_IWRITE;
- + break;
- + case MODE_A | MODE_PLUS:
- + flags = O_RDWR | O_APPEND | O_CREAT;
- + pmode = _S_IREAD | _S_IWRITE;
- + break;
- + default:
- + g_assert_not_reached ();
- + abort ();
- + }
- +
- + /* always open 'untranslated' */
- + fid = g_open (filename, flags | _O_BINARY, pmode);
- +
- + if (g_io_win32_get_debug_flag ())
- + {
- + g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
- + g_win32_print_access_mode (flags|_O_BINARY);
- + g_print (",%#o)=%d\n", pmode, fid);
- + }
- +
- + if (fid < 0)
- + {
- + g_set_error (error, G_FILE_ERROR,
- + g_file_error_from_errno (errno),
- + g_strerror (errno));
- + return (GIOChannel *)NULL;
- + }
- +
- + channel = g_io_channel_win32_new_fd (fid);
- +
- + /* XXX: move this to g_io_channel_win32_new_fd () */
- + channel->close_on_unref = TRUE;
- + channel->is_seekable = TRUE;
- +
- + /* g_io_channel_win32_new_fd sets is_readable and is_writeable to
- + * correspond to actual readability/writeability. Set to FALSE those
- + * that mode doesn't allow
- + */
- + switch (mode_num)
- + {
- + case MODE_R:
- + channel->is_writeable = FALSE;
- + break;
- + case MODE_W:
- + case MODE_A:
- + channel->is_readable = FALSE;
- + break;
- + case MODE_R | MODE_PLUS:
- + case MODE_W | MODE_PLUS:
- + case MODE_A | MODE_PLUS:
- + break;
- + default:
- + g_assert_not_reached ();
- + abort ();
- + }
- +
- + return channel;
- +}
- +
- +#ifdef G_OS_WIN32
- +
- +#undef g_io_channel_new_file
- +
- +/* Binary compatibility version. Not for newly compiled code. */
- +
- +GIOChannel *
- +g_io_channel_new_file (const gchar *filename,
- + const gchar *mode,
- + GError **error)
- +{
- + gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
- + GIOChannel *retval;
- +
- + if (utf8_filename == NULL)
- + return NULL;
- +
- + retval = g_io_channel_new_file_utf8 (utf8_filename, mode, error);
- +
- + g_free (utf8_filename);
- +
- + return retval;
- +}
- +
- +#endif
- +
- +static GIOStatus
- +g_io_win32_unimpl_set_flags (GIOChannel *channel,
- + GIOFlags flags,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + if (win32_channel->debug)
- + {
- + g_print ("g_io_win32_unimpl_set_flags: ");
- + g_win32_print_gioflags (flags);
- + g_print ("\n");
- + }
- +
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + G_IO_CHANNEL_ERROR_FAILED,
- + "Not implemented on Win32");
- +
- + return G_IO_STATUS_ERROR;
- +}
- +
- +static GIOFlags
- +g_io_win32_fd_get_flags_internal (GIOChannel *channel,
- + struct stat *st)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- + gchar c;
- + DWORD count;
- +
- + if (st->st_mode & _S_IFIFO)
- + {
- + channel->is_readable =
- + (PeekNamedPipe ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL, NULL) != 0) || GetLastError () == ERROR_BROKEN_PIPE;
- + channel->is_writeable =
- + (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
- + channel->is_seekable = FALSE;
- + }
- + else
- + {
- + channel->is_readable =
- + (ReadFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
- + channel->is_writeable =
- + (WriteFile ((HANDLE) _get_osfhandle (win32_channel->fd), &c, 0, &count, NULL) != 0);
- + channel->is_seekable = TRUE;
- + }
- +
- + /* XXX: G_IO_FLAG_APPEND */
- + /* XXX: G_IO_FLAG_NONBLOCK */
- +
- + return 0;
- +}
- +
- +static GIOFlags
- +g_io_win32_fd_get_flags (GIOChannel *channel)
- +{
- + struct stat st;
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + g_return_val_if_fail (win32_channel != NULL, 0);
- + g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
- +
- + if (0 == fstat (win32_channel->fd, &st))
- + return g_io_win32_fd_get_flags_internal (channel, &st);
- + else
- + return 0;
- +}
- +
- +static GIOFlags
- +g_io_win32_console_get_flags_internal (GIOChannel *channel)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
- + HANDLE handle = (HANDLE) _get_osfhandle (win32_channel->fd);
- + gchar c;
- + DWORD count;
- + INPUT_RECORD record;
- +
- + channel->is_readable = PeekConsoleInput (handle, &record, 1, &count);
- + channel->is_writeable = WriteFile (handle, &c, 0, &count, NULL);
- + channel->is_seekable = FALSE;
- +
- + return 0;
- +}
- +
- +static GIOFlags
- +g_io_win32_console_get_flags (GIOChannel *channel)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + g_return_val_if_fail (win32_channel != NULL, 0);
- + g_return_val_if_fail (win32_channel->type == G_IO_WIN32_CONSOLE, 0);
- +
- + return g_io_win32_console_get_flags_internal (channel);
- +}
- +
- +static GIOFlags
- +g_io_win32_msg_get_flags (GIOChannel *channel)
- +{
- + return 0;
- +}
- +
- +static GIOStatus
- +g_io_win32_sock_set_flags (GIOChannel *channel,
- + GIOFlags flags,
- + GError **err)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- + u_long arg;
- +
- + if (win32_channel->debug)
- + {
- + g_print ("g_io_win32_sock_set_flags: ");
- + g_win32_print_gioflags (flags);
- + g_print ("\n");
- + }
- +
- + if (flags & G_IO_FLAG_NONBLOCK)
- + {
- + arg = 1;
- + if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + G_IO_CHANNEL_ERROR_FAILED,
- + winsock_error_message (WSAGetLastError ()));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- + else
- + {
- + arg = 0;
- + if (ioctlsocket (win32_channel->fd, FIONBIO, &arg) == SOCKET_ERROR)
- + {
- + g_set_error (err, G_IO_CHANNEL_ERROR,
- + G_IO_CHANNEL_ERROR_FAILED,
- + winsock_error_message (WSAGetLastError ()));
- + return G_IO_STATUS_ERROR;
- + }
- + }
- +
- + return G_IO_STATUS_NORMAL;
- +}
- +
- +static GIOFlags
- +g_io_win32_sock_get_flags (GIOChannel *channel)
- +{
- + /* Could we do something here? */
- + return 0;
- +}
- +
- +static GIOFuncs win32_channel_msg_funcs = {
- + g_io_win32_msg_read,
- + g_io_win32_msg_write,
- + NULL,
- + g_io_win32_msg_close,
- + g_io_win32_msg_create_watch,
- + g_io_win32_free,
- + g_io_win32_unimpl_set_flags,
- + g_io_win32_msg_get_flags,
- +};
- +
- +static GIOFuncs win32_channel_fd_funcs = {
- + g_io_win32_fd_and_console_read,
- + g_io_win32_fd_and_console_write,
- + g_io_win32_fd_seek,
- + g_io_win32_fd_close,
- + g_io_win32_fd_create_watch,
- + g_io_win32_free,
- + g_io_win32_unimpl_set_flags,
- + g_io_win32_fd_get_flags,
- +};
- +
- +static GIOFuncs win32_channel_console_funcs = {
- + g_io_win32_fd_and_console_read,
- + g_io_win32_fd_and_console_write,
- + NULL,
- + g_io_win32_console_close,
- + g_io_win32_console_create_watch,
- + g_io_win32_free,
- + g_io_win32_unimpl_set_flags,
- + g_io_win32_console_get_flags,
- +};
- +
- +static GIOFuncs win32_channel_sock_funcs = {
- + g_io_win32_sock_read,
- + g_io_win32_sock_write,
- + NULL,
- + g_io_win32_sock_close,
- + g_io_win32_sock_create_watch,
- + g_io_win32_free,
- + g_io_win32_sock_set_flags,
- + g_io_win32_sock_get_flags,
- +};
- +
- +GIOChannel *
- +g_io_channel_win32_new_messages (guint hwnd)
- +{
- + GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- + GIOChannel *channel = (GIOChannel *)win32_channel;
- +
- + g_io_channel_init (channel);
- + g_io_channel_win32_init (win32_channel);
- + if (win32_channel->debug)
- + g_print ("g_io_channel_win32_new_messages: hwnd=%#x\n", hwnd);
- + channel->funcs = &win32_channel_msg_funcs;
- + win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
- + win32_channel->hwnd = (HWND) hwnd;
- +
- + /* XXX: check this. */
- + channel->is_readable = IsWindow (win32_channel->hwnd);
- + channel->is_writeable = IsWindow (win32_channel->hwnd);
- +
- + channel->is_seekable = FALSE;
- +
- + return channel;
- +}
- +
- +static GIOChannel *
- +g_io_channel_win32_new_fd_internal (gint fd,
- + struct stat *st)
- +{
- + GIOWin32Channel *win32_channel;
- + GIOChannel *channel;
- +
- + win32_channel = g_new (GIOWin32Channel, 1);
- + channel = (GIOChannel *)win32_channel;
- +
- + g_io_channel_init (channel);
- + g_io_channel_win32_init (win32_channel);
- +
- + win32_channel->fd = fd;
- +
- + if (win32_channel->debug)
- + g_print ("g_io_channel_win32_new_fd: %u\n", fd);
- + if (st->st_mode & _S_IFCHR) /* console */
- + {
- + channel->funcs = &win32_channel_console_funcs;
- + win32_channel->type = G_IO_WIN32_CONSOLE;
- + g_io_win32_console_get_flags_internal (channel);
- + }
- + else
- + {
- + channel->funcs = &win32_channel_fd_funcs;
- + win32_channel->type = G_IO_WIN32_FILE_DESC;
- + g_io_win32_fd_get_flags_internal (channel, st);
- + }
- +
- + return channel;
- +}
- +
- +GIOChannel *
- +g_io_channel_win32_new_fd (gint fd)
- +{
- + struct stat st;
- +
- + if (fstat (fd, &st) == -1)
- + {
- + g_warning (G_STRLOC ": %d isn't a C library file descriptor", fd);
- + return NULL;
- + }
- +
- + return g_io_channel_win32_new_fd_internal (fd, &st);
- +}
- +
- +gint
- +g_io_channel_win32_get_fd (GIOChannel *channel)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + return win32_channel->fd;
- +}
- +
- +GIOChannel *
- +g_io_channel_win32_new_socket (int socket)
- +{
- + GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
- + GIOChannel *channel = (GIOChannel *)win32_channel;
- +
- + g_io_channel_init (channel);
- + g_io_channel_win32_init (win32_channel);
- + if (win32_channel->debug)
- + g_print ("g_io_channel_win32_new_socket: sockfd=%d\n", socket);
- + channel->funcs = &win32_channel_sock_funcs;
- + win32_channel->type = G_IO_WIN32_SOCKET;
- + win32_channel->fd = socket;
- +
- + channel->is_readable = TRUE;
- + channel->is_writeable = TRUE;
- + channel->is_seekable = FALSE;
- +
- + return channel;
- +}
- +
- +GIOChannel *
- +g_io_channel_unix_new (gint fd)
- +{
- + gboolean is_fd, is_socket;
- + struct stat st;
- + int optval, optlen;
- +
- + is_fd = (fstat (fd, &st) == 0);
- +
- + optlen = sizeof (optval);
- + is_socket = (getsockopt (fd, SOL_SOCKET, SO_TYPE, (char *) &optval, &optlen) != SOCKET_ERROR);
- +
- + if (is_fd && is_socket)
- + g_warning (G_STRLOC ": %d is both a file descriptor and a socket, file descriptor interpretation assumed.", fd);
- +
- + if (is_fd)
- + return g_io_channel_win32_new_fd_internal (fd, &st);
- +
- + if (is_socket)
- + return g_io_channel_win32_new_socket(fd);
- +
- + g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
- +
- + return NULL;
- +}
- +
- +gint
- +g_io_channel_unix_get_fd (GIOChannel *channel)
- +{
- + return g_io_channel_win32_get_fd (channel);
- +}
- +
- +void
- +g_io_channel_win32_set_debug (GIOChannel *channel,
- + gboolean flag)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + win32_channel->debug = flag;
- +}
- +
- +gint
- +g_io_channel_win32_poll (GPollFD *fds,
- + gint n_fds,
- + gint timeout)
- +{
- + int result;
- +
- + g_return_val_if_fail (n_fds >= 0, 0);
- +
- + result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
- +
- + return result;
- +}
- +
- +void
- +g_io_channel_win32_make_pollfd (GIOChannel *channel,
- + GIOCondition condition,
- + GPollFD *fd)
- +{
- + GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
- +
- + switch (win32_channel->type)
- + {
- + case G_IO_WIN32_FILE_DESC:
- + if (win32_channel->data_avail_event == NULL)
- + create_events (win32_channel);
- +
- + fd->fd = (gint) win32_channel->data_avail_event;
- +
- + if (win32_channel->thread_id == 0 && (condition & G_IO_IN))
- + {
- + if (condition & G_IO_IN)
- + create_thread (win32_channel, condition, read_thread);
- + else if (condition & G_IO_OUT)
- + create_thread (win32_channel, condition, write_thread);
- + }
- + break;
- +
- + case G_IO_WIN32_CONSOLE:
- + fd->fd = (gint) _get_osfhandle (win32_channel->fd);
- + break;
- +
- + case G_IO_WIN32_SOCKET:
- + fd->fd = (int) WSACreateEvent ();
- + break;
- +
- + case G_IO_WIN32_WINDOWS_MESSAGES:
- + fd->fd = G_WIN32_MSG_HANDLE;
- + break;
- +
- + default:
- + g_assert_not_reached ();
- + abort ();
- + }
- +
- + fd->events = condition;
- +}
- +
- +/* Binary compatibility */
- +GIOChannel *
- +g_io_channel_win32_new_stream_socket (int socket)
- +{
- + return g_io_channel_win32_new_socket (socket);
- +}
- +
- +#define __G_IO_WIN32_C__
- +#include "galiasdef.c"
- diff --git a/clients/Instantbird/gstrcmp0.c b/clients/Instantbird/gstrcmp0.c
- new file mode 100755
- index 0000000..d21c31a
- --- /dev/null
- +++ b/clients/Instantbird/gstrcmp0.c
- @@ -0,0 +1,22 @@
- +/**
- + * g_strcmp0:
- + * @str1: a C string or %NULL
- + * @str2: another C string or %NULL
- + *
- + * Compares @str1 and @str2 like strcmp(). Handles %NULL
- + * gracefully by sorting it before non-%NULL strings.
- + *
- + * Returns: -1, 0 or 1, if @str1 is <, == or > than @str2.
- + *
- + * Since: 2.16
- + */
- +int
- +g_strcmp0 (const char *str1,
- + const char *str2)
- +{
- + if (!str1)
- + return -(str1 != str2);
- + if (!str2)
- + return str1 != str2;
- + return strcmp (str1, str2);
- +}
- diff --git a/clients/Instantbird/linux/Makefile.in b/clients/Instantbird/linux/Makefile.in
- new file mode 100755
- index 0000000..2916764
- --- /dev/null
- +++ b/clients/Instantbird/linux/Makefile.in
- @@ -0,0 +1,62 @@
- +DEPTH = ../../../..
- +topsrcdir = @top_srcdir@
- +srcdir = @srcdir@
- +VPATH = @srcdir@
- +PROTOCOL = msn_pecan
- +
- +include $(srcdir)/../prpl.mk
- +
- +DEFINES += \
- + -DHAVE_LIBPURPLE \
- + -D_XOPEN_SOURCE \
- + -DINSTANTBIRD \
- + -DPECAN_CVR \
- + -DPECAN_USE_PSM
- +
- +CSRCS = \
- + giochannel.c giounix.c gstrcmp0.c \
- + msn.c \
- + nexus.c \
- + notification.c \
- + page.c \
- + session.c \
- + switchboard.c \
- + sync.c \
- + pn_log.c \
- + pn_printf.c \
- + pn_util.c \
- + pn_buffer.c \
- + pn_error.c \
- + pn_status.c \
- + pn_oim.c \
- + pn_dp_manager.c \
- + cmd/cmdproc.c \
- + cmd/command.c \
- + cmd/msg.c \
- + cmd/table.c \
- + cmd/transaction.c \
- + io/pn_parser.c \
- + ab/pn_group.c \
- + ab/pn_contact.c \
- + ab/pn_contactlist.c \
- + io/pn_stream.c \
- + io/pn_node.c \
- + io/pn_cmd_server.c \
- + io/pn_http_server.c \
- + io/pn_ssl_conn.c \
- + cvr/pn_peer_call.c \
- + cvr/pn_peer_link.c \
- + cvr/pn_peer_msg.c \
- + cvr/pn_msnobj.c \
- + libpurple/xfer.c \
- + fix_purple.c \
- + $(NULL)
- +
- +export::
- + mkdir -p cmd
- + mkdir -p io
- + mkdir -p ab
- + mkdir -p cvr
- + mkdir -p libpurple
- +
- +include $(srcdir)/../prpl-rules.mk
- diff --git a/clients/Instantbird/macosx/Makefile.in b/clients/Instantbird/macosx/Makefile.in
- new file mode 100755
- index 0000000..7f55408
- --- /dev/null
- +++ b/clients/Instantbird/macosx/Makefile.in
- @@ -0,0 +1,63 @@
- +DEPTH = ../../../..
- +topsrcdir = @top_srcdir@
- +srcdir = @srcdir@
- +VPATH = @srcdir@
- +PROTOCOL = msn_pecan
- +
- +include $(srcdir)/../prpl.mk
- +
- +DEFINES += \
- + -DHAVE_LIBPURPLE \
- + -D_XOPEN_SOURCE \
- + -DINSTANTBIRD \
- + -DINTERNAL_MAINLOOP \
- + -DPECAN_CVR \
- + -DPECAN_USE_PSM
- +
- +CSRCS = \
- + giochannel.c giounix.c gstrcmp0.c \
- + msn.c \
- + nexus.c \
- + notification.c \
- + page.c \
- + session.c \
- + switchboard.c \
- + sync.c \
- + pn_log.c \
- + pn_printf.c \
- + pn_util.c \
- + pn_buffer.c \
- + pn_error.c \
- + pn_status.c \
- + pn_oim.c \
- + pn_dp_manager.c \
- + cmd/cmdproc.c \
- + cmd/command.c \
- + cmd/msg.c \
- + cmd/table.c \
- + cmd/transaction.c \
- + io/pn_parser.c \
- + ab/pn_group.c \
- + ab/pn_contact.c \
- + ab/pn_contactlist.c \
- + io/pn_stream.c \
- + io/pn_node.c \
- + io/pn_cmd_server.c \
- + io/pn_http_server.c \
- + io/pn_ssl_conn.c \
- + cvr/pn_peer_call.c \
- + cvr/pn_peer_link.c \
- + cvr/pn_peer_msg.c \
- + cvr/pn_msnobj.c \
- + libpurple/xfer.c \
- + fix_purple.c \
- + $(NULL)
- +
- +export::
- + mkdir -p cmd
- + mkdir -p io
- + mkdir -p ab
- + mkdir -p cvr
- + mkdir -p libpurple
- +
- +include $(srcdir)/../prpl-rules.mk
- diff --git a/clients/Instantbird/win32/Makefile.in b/clients/Instantbird/win32/Makefile.in
- new file mode 100755
- index 0000000..11c136c
- --- /dev/null
- +++ b/clients/Instantbird/win32/Makefile.in
- @@ -0,0 +1,63 @@
- +DEPTH = ../../../..
- +topsrcdir = @top_srcdir@
- +srcdir = @srcdir@
- +VPATH = @srcdir@
- +PROTOCOL = msn_pecan
- +
- +include $(srcdir)/../prpl.mk
- +
- +DEFINES += \
- + -DHAVE_LIBPURPLE \
- + -D_XOPEN_SOURCE \
- + -DINSTANTBIRD \
- + -DINTERNAL_MAINLOOP \
- + -DPECAN_CVR \
- + -DPECAN_USE_PSM
- +
- +CSRCS = \
- + giochannel.c giowin32.c gstrcmp0.c \
- + msn.c \
- + nexus.c \
- + notification.c \
- + page.c \
- + session.c \
- + switchboard.c \
- + sync.c \
- + pn_log.c \
- + pn_printf.c \
- + pn_util.c \
- + pn_buffer.c \
- + pn_error.c \
- + pn_status.c \
- + pn_oim.c \
- + pn_dp_manager.c \
- + cmd/cmdproc.c \
- + cmd/command.c \
- + cmd/msg.c \
- + cmd/table.c \
- + cmd/transaction.c \
- + io/pn_parser.c \
- + ab/pn_group.c \
- + ab/pn_contact.c \
- + ab/pn_contactlist.c \
- + io/pn_stream.c \
- + io/pn_node.c \
- + io/pn_cmd_server.c \
- + io/pn_http_server.c \
- + io/pn_ssl_conn.c \
- + cvr/pn_peer_call.c \
- + cvr/pn_peer_link.c \
- + cvr/pn_peer_msg.c \
- + cvr/pn_msnobj.c \
- + libpurple/xfer.c \
- + fix_purple.c \
- + $(NULL)
- +
- +export::
- + mkdir -p cmd
- + mkdir -p io
- + mkdir -p ab
- + mkdir -p cvr
- + mkdir -p libpurple
- +
- +include $(srcdir)/../prpl-rules.mk
- diff --git a/msn.c b/msn.c
- index 9db608c..560da52 100644
- --- a/msn.c
- +++ b/msn.c
- @@ -1922,6 +1922,9 @@ init_plugin (PurplePlugin *plugin)
- purple_prefs_remove ("/plugins/prpl/msn");
- }
- +#ifdef INSTANTBIRD
- +PURPLE_INIT_PLUGIN(msn_pecan, init_plugin, info);
- +#else
- #ifndef STATIC_PECAN
- G_MODULE_EXPORT gboolean
- purple_init_plugin(PurplePlugin *plugin)
- @@ -1941,3 +1944,4 @@ purple_init_msn_pecan_plugin(void)
- return purple_plugin_register(plugin);
- }
- #endif
- +#endif /* INSTANTBIRD */
- --
- 1.6.5
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement