#include <ctype.h>
#include "gskstream.h"
#include "gskstreamconnection.h"
#include "gskerror.h"
#include "gskmacros.h"
#include "gskutils.h" /* for gsk_escape_memory() */
#include "debug.h"
/* parent classes */
static GObjectClass *parent_class = NULL;
/* ugh... */
#define DEBUG_PRINT_HEADER_FLAGS(flags, fctname) \
_GSK_DEBUG_PRINTF((flags), \
("running %s on %s[%p]", \
fctname, \
g_type_name(G_OBJECT_TYPE(stream)), \
stream))
#define DEBUG_PRINT_HEADER(fctname) DEBUG_PRINT_HEADER_FLAGS(GSK_DEBUG_STREAM, fctname)
/* ========== GskStream =========== */
/* --- i/o methods --- */
/**
* gsk_stream_read:
* @stream: the stream to attempt to read data from.
* @buffer: the buffer to fill with data.
* @buffer_length: the maximum data to copy into the buffer.
* @error: optional place to store a GError if something goes wrong.
*
* Read up to @buffer_length bytes into @buffer,
* returning the amount read. It may return 0;
* this does not indicate an end-of-file.
*
* returns: the number of bytes read into @buffer.
*/
gsize
gsk_stream_read (GskStream *stream,
gpointer buffer,
gsize buffer_length,
GError **error)
{
GskStreamClass *class = GSK_STREAM_GET_CLASS (stream);
gsize rv;
DEBUG_PRINT_HEADER ("gsk_stream_read");
if (error != NULL && *error != NULL)
return 0;
if (gsk_io_get_is_connecting (stream))
return 0;
g_object_ref (stream);
rv = (*class->raw_read) (stream, buffer, buffer_length, error);
if (stream->never_partial_reads)
g_return_val_if_fail (rv == buffer_length, rv);
if (GSK_IS_DEBUGGING (STREAM_DATA))
{
char *text = gsk_escape_memory (buffer, rv);
g_printerr ("%s::read() = \"%s\"\n", G_OBJECT_TYPE_NAME (stream), text);
g_free (text);
}
g_object_unref (stream);
return rv;
}
/**
* gsk_stream_write:
* @stream: the stream to attempt to write data to.
* @buffer: the buffer to write from.
* @buffer_length: the number of bytes in buffer.
* @error: optional place to store a GError if something goes wrong.
*
* Write up to @buffer_length bytes into @buffer,
* returning the amount written. It may return 0;
* this does not indicate an error by itself.
*
* returns: the number of bytes written.
*/
gsize
gsk_stream_write (GskStream *stream,
gconstpointer buffer,
gsize buffer_length,
GError **error)
{
guint written = 0;
GskStreamClass *class = GSK_STREAM_GET_CLASS (stream);
_GSK_DEBUG_PRINTF(GSK_DEBUG_STREAM,
("running %s on %s[%p]. buffer_length=%u.",
"gsk_stream_write",
g_type_name(G_OBJECT_TYPE(stream)),
stream, (guint)buffer_length));
if (error != NULL && *error != NULL)
return 0;
if (buffer_length == 0)
return 0;
if (gsk_io_get_is_connecting (stream))
{
_GSK_DEBUG_PRINTF(GSK_DEBUG_STREAM,
("gsk_stream_write: returning 0 because stream is still connecting"));
return 0;
}
g_object_ref (stream);
g_return_val_if_fail (class->raw_write != NULL, 0);
written = (*class->raw_write) (stream, buffer, buffer_length, error);
if (GSK_IS_DEBUGGING (STREAM_DATA))
{
char *text = gsk_escape_memory (buffer, written);
g_printerr ("%s::write() = \"%s\"\n", G_OBJECT_TYPE_NAME (stream), text);
g_free (text);
}
g_assert (written <= buffer_length);
if (stream->never_partial_writes)
g_return_val_if_fail (written == buffer_length, buffer_length);
g_object_unref (stream);
return written;
}
/* read into buffer */
/**
* gsk_stream_read_buffer:
* @stream: the stream to attempt to read data from.
* @buffer: the buffer to copy data into.
* @error: optional place to store a GError if something goes wrong.
*
* Read data from the stream directly into a #GskBuffer.
*
* returns: the number of bytes read into @buffer.
*/
gsize
gsk_stream_read_buffer (GskStream *stream,
GskBuffer *buffer,
GError **error)
{
GskStreamClass *class = GSK_STREAM_GET_CLASS (stream);
gboolean debug_data = GSK_IS_DEBUGGING (STREAM_DATA);
if (gsk_io_get_is_connecting (stream))
return 0;
if (!debug_data && class->raw_read_buffer)
return (*class->raw_read_buffer) (stream, buffer, error);
else
{
char tmp_area[8192];
guint size = 8192;
gsize read;
/* tmp_area = g_alloca (size); */
g_object_ref (stream);
read = gsk_stream_read (stream, tmp_area, size, error);
if (read > 0)
gsk_buffer_append (buffer, tmp_area, read);
if (debug_data)
{
char *str = gsk_escape_memory (tmp_area, read);
g_printerr ("gsk_stream_read_buffer: \"%s\"\n", str);
g_free (str);
}
g_object_unref (stream);
return read;
}
}
/* write from buffer */
/**
* gsk_stream_write_buffer:
* @stream: the stream to attempt to write data to.
* @buffer: the buffer to get data from.
* @error: optional place to store a GError if something goes wrong.
*
* Write data to the stream directly from a #GskBuffer.
* Data written from the buffer is removed from it.
*
* returns: the number of bytes written from @buffer.
*/
gsize
gsk_stream_write_buffer (GskStream *stream,
GskBuffer *buffer,
GError **error)
{
GskStreamClass *class = GSK_STREAM_GET_CLASS (stream);
gboolean debug_data = GSK_IS_DEBUGGING (STREAM_DATA);
if (gsk_io_get_is_connecting (stream))
return 0;
if (!debug_data && class->raw_write_buffer)
return (*class->raw_write_buffer) (stream, buffer, error);
else
{
char *tmp_area;
guint size = 8192;
guint read;
tmp_area = g_alloca (size);
g_object_ref (stream);
read = gsk_buffer_peek (buffer, tmp_area, size);
if (read > 0)
{
gsize written = gsk_stream_write (stream, tmp_area, read, error);
if (written > 0)
gsk_buffer_discard (buffer, written);
if (debug_data)
{
char *text = gsk_escape_memory (tmp_area, written);
g_printerr ("gsk_stream_write_buffer[%s]: \"%s\"\n",
G_OBJECT_TYPE_NAME (stream), text);
g_free (text);
}
g_object_unref (stream);
return written;
}
else
{
if (debug_data)
g_printerr ("gsk_stream_write_buffer[%s]: source buffer was empty\n",
G_OBJECT_TYPE_NAME (stream));
}
g_object_unref (stream);
return read;
}
}
/* --- functions --- */
static void
gsk_stream_init (GskStream *stream)
{
}
static void
gsk_stream_class_init (GskStreamClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
parent_class = g_type_class_peek_parent (object_class);
}
GType gsk_stream_get_type()
{
static GType stream_type = 0;
if (!stream_type)
{
static const GTypeInfo stream_info =
{
sizeof(GskStreamClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gsk_stream_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskStream),
0, /* n_preallocs */
(GInstanceInitFunc) gsk_stream_init,
NULL /* value_table */
};
stream_type = g_type_register_static (GSK_TYPE_IO,
"GskStream",
&stream_info,
G_TYPE_FLAG_ABSTRACT);
}
return stream_type;
}
/**
* gsk_stream_attach:
* @input_stream: the input stream whose read-end will be trapped.
* @output_stream: the output stream whose write-end will be trapped.
* @error: optional error return location.
*
* Attach the read end of @input_stream
* to the write end of @output_stream,
* returning an error if anything goes wrong.
*
* returns: whether the connection was successful.
*/
gboolean
gsk_stream_attach (GskStream *input_stream,
GskStream *output_stream,
GError **error)
{
GskStreamConnection *connection = gsk_stream_connection_new (input_stream, output_stream, error);
if (connection != NULL)
{
g_object_unref (connection);
return TRUE;
}
return FALSE;
}
/**
* gsk_stream_attach_pair:
* @stream_a: one of the two streams to attach together.
* @stream_b: one of the two streams to attach together.
* @error: optional error return location.
*
* Attach a's input to b's output and vice versa.
*
* returns: whether the connection was successful.
*/
gboolean gsk_stream_attach_pair (GskStream *stream_a,
GskStream *stream_b,
GError **error)
{
GskStreamConnection *ab = gsk_stream_connection_new (stream_a, stream_b, error);
GskStreamConnection *ba;
if (ab == NULL)
return FALSE;
ba = gsk_stream_connection_new (stream_b, stream_a, error);
if (ba == NULL)
{
gsk_stream_connection_detach (ab);
g_object_unref (ab);
return FALSE;
}
g_object_unref (ab);
g_object_unref (ba);
return TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1