[glib] Add g_data_input_stream_read_upto{,async,finish}
- From: Ryan Lortie <ryanl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Add g_data_input_stream_read_upto{,async,finish}
- Date: Mon, 13 Sep 2010 17:14:39 +0000 (UTC)
commit 2e78d07f86d70de274f126a3ff00bd4af90a5c90
Author: Ryan Lortie <desrt desrt ca>
Date: Tue Mar 23 01:12:01 2010 -0500
Add g_data_input_stream_read_upto{,async,finish}
These functions are meant to replace the read_until() flavour, with the
following improvements:
- consistency between the synchronous and asynchronous versions as to
if the separator character is read (it never is).
- support for using a nul byte as a separator character by way of
addition of a length parameter which allows stop_chars to be treated
as a byte array rather than a nul-terminated string.
The read_until() functions are not yet formally deprecated, but a note
has been added to the documentation warning not to use them as they will
be in the future.
This is bug #584284.
docs/reference/gio/gio-sections.txt | 3 +
gio/gdatainputstream.c | 257 ++++++++++++++++++++++++++++-------
gio/gdatainputstream.h | 66 ++++++----
gio/gio.symbols | 3 +
gio/tests/data-input-stream.c | 61 ++++++++-
5 files changed, 312 insertions(+), 78 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 77011b9..368797c 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -671,6 +671,9 @@ g_data_input_stream_read_uint64
g_data_input_stream_read_line
g_data_input_stream_read_line_async
g_data_input_stream_read_line_finish
+g_data_input_stream_read_upto
+g_data_input_stream_read_upto_async
+g_data_input_stream_read_upto_finish
g_data_input_stream_read_until
g_data_input_stream_read_until_async
g_data_input_stream_read_until_finish
diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c
index ad8bf5e..7743d56 100644
--- a/gio/gdatainputstream.c
+++ b/gio/gdatainputstream.c
@@ -30,6 +30,7 @@
#include "gioerror.h"
#include "glibintl.h"
+#include <string.h>
/**
* SECTION:gdatainputstream
@@ -811,7 +812,8 @@ g_data_input_stream_read_line (GDataInputStream *stream,
static gssize
scan_for_chars (GDataInputStream *stream,
gsize *checked_out,
- const char *stop_chars)
+ const char *stop_chars,
+ gssize stop_chars_len)
{
GBufferedInputStream *bstream;
const char *buffer;
@@ -819,8 +821,10 @@ scan_for_chars (GDataInputStream *stream,
int i;
gsize available, checked;
const char *stop_char;
+ const char *stop_end;
bstream = G_BUFFERED_INPUT_STREAM (stream);
+ stop_end = stop_chars + stop_chars_len;
checked = *checked_out;
@@ -831,7 +835,7 @@ scan_for_chars (GDataInputStream *stream,
for (i = 0; checked < available && i < peeked; i++)
{
- for (stop_char = stop_chars; *stop_char != '\0'; stop_char++)
+ for (stop_char = stop_chars; stop_char != stop_end; stop_char++)
{
if (buffer[i] == *stop_char)
return (start + i);
@@ -858,6 +862,12 @@ scan_for_chars (GDataInputStream *stream,
* Note that, in contrast to g_data_input_stream_read_until_async(),
* this function consumes the stop character that it finds.
*
+ * Don't use this function in new code. Its functionality is
+ * inconsistent with g_data_input_stream_read_until_async(). Both
+ * functions will be marked as deprecated in a future release. Use
+ * g_data_input_stream_read_upto() instead, but note that that function
+ * does not consume the stop character.
+ *
* Returns: a string with the data that was read before encountering
* any of the stop characters. Set @length to a #gsize to get the length
* of the string. This function will return %NULL on an error.
@@ -870,59 +880,24 @@ g_data_input_stream_read_until (GDataInputStream *stream,
GError **error)
{
GBufferedInputStream *bstream;
- gsize checked;
- gssize found_pos;
- gssize res;
- int stop_char_len;
- char *data_until;
-
- g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
+ gchar *result;
bstream = G_BUFFERED_INPUT_STREAM (stream);
- stop_char_len = 1;
- checked = 0;
+ result = g_data_input_stream_read_upto (stream, stop_chars, -1,
+ length, cancellable, error);
- while ((found_pos = scan_for_chars (stream, &checked, stop_chars)) == -1)
+ /* If we're not at end of stream then we have a stop_char to consume. */
+ if (result != NULL && g_buffered_input_stream_get_available (bstream) > 0)
{
- if (g_buffered_input_stream_get_available (bstream) ==
- g_buffered_input_stream_get_buffer_size (bstream))
- g_buffered_input_stream_set_buffer_size (bstream,
- 2 * g_buffered_input_stream_get_buffer_size (bstream));
+ gsize res;
+ gchar b;
- res = g_buffered_input_stream_fill (bstream, -1, cancellable, error);
- if (res < 0)
- return NULL;
- if (res == 0)
- {
- /* End of stream */
- if (g_buffered_input_stream_get_available (bstream) == 0)
- {
- if (length)
- *length = 0;
- return NULL;
- }
- else
- {
- found_pos = checked;
- stop_char_len = 0;
- break;
- }
- }
+ res = g_input_stream_read (G_INPUT_STREAM (stream), &b, 1, NULL, NULL);
+ g_assert (res == 1);
}
- data_until = g_malloc (found_pos + stop_char_len + 1);
-
- res = g_input_stream_read (G_INPUT_STREAM (stream),
- data_until,
- found_pos + stop_char_len,
- NULL, NULL);
- if (length)
- *length = (gsize)found_pos;
- g_warn_if_fail (res == found_pos + stop_char_len);
- data_until[found_pos] = 0;
-
- return data_until;
+ return result;
}
typedef struct
@@ -935,6 +910,7 @@ typedef struct
GCancellable *cancellable;
gchar *stop_chars;
+ gssize stop_chars_len;
gchar *line;
gsize length;
} GDataInputStreamReadData;
@@ -1010,7 +986,8 @@ g_data_input_stream_read_line_ready (GObject *object,
{
found_pos = scan_for_chars (data->stream,
&data->checked,
- data->stop_chars);
+ data->stop_chars,
+ data->stop_chars_len);
newline_len = 0;
}
else
@@ -1062,6 +1039,7 @@ g_data_input_stream_read_data_free (gpointer user_data)
static void
g_data_input_stream_read_async (GDataInputStream *stream,
const gchar *stop_chars,
+ gssize stop_chars_len,
gint io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -1075,7 +1053,10 @@ g_data_input_stream_read_async (GDataInputStream *stream,
if (cancellable)
g_object_ref (cancellable);
data->cancellable = cancellable;
- data->stop_chars = g_strdup (stop_chars);
+ if (stop_chars_len == -1)
+ stop_chars_len = strlen (stop_chars);
+ data->stop_chars = g_memdup (stop_chars, stop_chars_len);
+ data->stop_chars_len = stop_chars_len;
data->io_priority = io_priority;
data->last_saw_cr = FALSE;
data->checked = 0;
@@ -1142,7 +1123,7 @@ g_data_input_stream_read_line_async (GDataInputStream *stream,
g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
- g_data_input_stream_read_async (stream, NULL, io_priority,
+ g_data_input_stream_read_async (stream, NULL, 0, io_priority,
cancellable, callback, user_data,
g_data_input_stream_read_line_async);
}
@@ -1168,6 +1149,11 @@ g_data_input_stream_read_line_async (GDataInputStream *stream,
* can then call g_data_input_stream_read_until_finish() to get
* the result of the operation.
*
+ * Don't use this function in new code. Its functionality is
+ * inconsistent with g_data_input_stream_read_until(). Both functions
+ * will be marked as deprecated in a future release. Use
+ * g_data_input_stream_read_upto_async() instead.
+ *
* Since: 2.20
*/
void
@@ -1182,7 +1168,7 @@ g_data_input_stream_read_until_async (GDataInputStream *stream,
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
g_return_if_fail (stop_chars != NULL);
- g_data_input_stream_read_async (stream, stop_chars, io_priority,
+ g_data_input_stream_read_async (stream, stop_chars, -1, io_priority,
cancellable, callback, user_data,
g_data_input_stream_read_until_async);
}
@@ -1245,3 +1231,172 @@ g_data_input_stream_read_until_finish (GDataInputStream *stream,
return g_data_input_stream_read_finish (stream, result, length, error);
}
+
+/**
+ * g_data_input_stream_read_upto:
+ * @stream: a #GDataInputStream
+ * @stop_chars: characters to terminate the read
+ * @stop_chars_len: length of @stop_chars. May be -1 if @stop_chars is
+ * nul-terminated
+ * @length: a #gsize to get the length of the data read in
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @error: #GError for error reporting
+ *
+ * Reads a string from the data input stream, up to the first
+ * occurrence of any of the stop characters.
+ *
+ * In contrast to g_data_input_stream_read_until(), this function
+ * does <emphasis>not</emphasis> consume the stop character. You have
+ * to use g_data_input_stream_read_byte() to get it before calling
+ * g_data_input_stream_read_upto() again.
+ *
+ * Note that @stop_chars may contain '\0' if @stop_chars_len is
+ * specified.
+ *
+ * Returns: a string with the data that was read before encountering
+ * any of the stop characters. Set @length to a #gsize to get the length
+ * of the string. This function will return %NULL on an error
+ *
+ * Since: 2.24
+ */
+char *
+g_data_input_stream_read_upto (GDataInputStream *stream,
+ const gchar *stop_chars,
+ gssize stop_chars_len,
+ gsize *length,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GBufferedInputStream *bstream;
+ gsize checked;
+ gssize found_pos;
+ gssize res;
+ char *data_until;
+
+ g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
+
+ if (stop_chars_len < 0)
+ stop_chars_len = strlen (stop_chars);
+
+ bstream = G_BUFFERED_INPUT_STREAM (stream);
+
+ checked = 0;
+
+ while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len)) == -1)
+ {
+ if (g_buffered_input_stream_get_available (bstream) ==
+ g_buffered_input_stream_get_buffer_size (bstream))
+ g_buffered_input_stream_set_buffer_size (bstream,
+ 2 * g_buffered_input_stream_get_buffer_size (bstream));
+
+ res = g_buffered_input_stream_fill (bstream, -1, cancellable, error);
+ if (res < 0)
+ return NULL;
+ if (res == 0)
+ {
+ /* End of stream */
+ if (g_buffered_input_stream_get_available (bstream) == 0)
+ {
+ if (length)
+ *length = 0;
+ return NULL;
+ }
+ else
+ {
+ found_pos = checked;
+ break;
+ }
+ }
+ }
+
+ data_until = g_malloc (found_pos + 1);
+
+ res = g_input_stream_read (G_INPUT_STREAM (stream),
+ data_until,
+ found_pos,
+ NULL, NULL);
+ if (length)
+ *length = (gsize)found_pos;
+ g_warn_if_fail (res == found_pos);
+ data_until[found_pos] = 0;
+
+ return data_until;
+}
+
+/**
+ * g_data_input_stream_read_upto_async:
+ * @stream: a #GDataInputStream
+ * @stop_chars: characters to terminate the read
+ * @stop_chars_len: length of @stop_chars. May be -1 if @stop_chars is
+ * nul-terminated
+ * @cancellable: optional #GCancellable object, %NULL to ignore
+ * @callback: callback to call when the request is satisfied
+ * @user_data: the data to pass to callback function
+ *
+ * The asynchronous version of g_data_input_stream_read_upto().
+ * It is an error to have two outstanding calls to this function.
+ *
+ * In contrast to g_data_input_stream_read_until(), this function
+ * does <emphasis>not</emphasis> consume the stop character. You have
+ * to use g_data_input_stream_read_byte() to get it before calling
+ * g_data_input_stream_read_upto() again.
+ *
+ * Note that @stop_chars may contain '\0' if @stop_chars_len is
+ * specified.
+ *
+ * When the operation is finished, @callback will be called. You
+ * can then call g_data_input_stream_read_upto_finish() to get
+ * the result of the operation.
+ *
+ * Since: 2.24
+ */
+void
+g_data_input_stream_read_upto_async (GDataInputStream *stream,
+ const gchar *stop_chars,
+ gssize stop_chars_len,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+ g_return_if_fail (stop_chars != NULL);
+
+ g_data_input_stream_read_async (stream, stop_chars, stop_chars_len, io_priority,
+ cancellable, callback, user_data,
+ g_data_input_stream_read_upto_async);
+}
+
+/**
+ * g_data_input_stream_read_upto_finish:
+ * @stream: a #GDataInputStream
+ * @result: the #GAsyncResult that was provided to the callback
+ * @length: a #gsize to get the length of the data read in
+ * @error: #GError for error reporting
+ *
+ * Finish an asynchronous call started by
+ * g_data_input_stream_read_upto_async().
+ *
+ * Note that this function does <emphasis>not</emphasis> consume the
+ * stop character. You have to use g_data_input_stream_read_byte() to
+ * get it before calling g_data_input_stream_read_upto_async() again.
+ *
+ * Returns: a string with the data that was read before encountering
+ * any of the stop characters. Set @length to a #gsize to get the length
+ * of the string. This function will return %NULL on an error.
+ *
+ * Since: 2.24
+ */
+gchar *
+g_data_input_stream_read_upto_finish (GDataInputStream *stream,
+ GAsyncResult *result,
+ gsize *length,
+ GError **error)
+{
+ g_return_val_if_fail (
+ g_simple_async_result_is_valid (result, G_OBJECT (stream),
+ g_data_input_stream_read_upto_async), NULL);
+
+ return g_data_input_stream_read_finish (stream, result, length, error);
+}
diff --git a/gio/gdatainputstream.h b/gio/gdatainputstream.h
index 0e42317..e5724d5 100644
--- a/gio/gdatainputstream.h
+++ b/gio/gdatainputstream.h
@@ -72,36 +72,36 @@ GType g_data_input_stream_get_type (void) G_GNUC_CO
GDataInputStream * g_data_input_stream_new (GInputStream *base_stream);
void g_data_input_stream_set_byte_order (GDataInputStream *stream,
- GDataStreamByteOrder order);
+ GDataStreamByteOrder order);
GDataStreamByteOrder g_data_input_stream_get_byte_order (GDataInputStream *stream);
void g_data_input_stream_set_newline_type (GDataInputStream *stream,
- GDataStreamNewlineType type);
+ GDataStreamNewlineType type);
GDataStreamNewlineType g_data_input_stream_get_newline_type (GDataInputStream *stream);
guchar g_data_input_stream_read_byte (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
gint16 g_data_input_stream_read_int16 (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
guint16 g_data_input_stream_read_uint16 (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
gint32 g_data_input_stream_read_int32 (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
guint32 g_data_input_stream_read_uint32 (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
gint64 g_data_input_stream_read_int64 (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
guint64 g_data_input_stream_read_uint64 (GDataInputStream *stream,
- GCancellable *cancellable,
- GError **error);
+ GCancellable *cancellable,
+ GError **error);
char * g_data_input_stream_read_line (GDataInputStream *stream,
- gsize *length,
- GCancellable *cancellable,
- GError **error);
+ gsize *length,
+ GCancellable *cancellable,
+ GError **error);
void g_data_input_stream_read_line_async (GDataInputStream *stream,
gint io_priority,
GCancellable *cancellable,
@@ -112,12 +112,12 @@ char * g_data_input_stream_read_line_finish (GDataInputStrea
gsize *length,
GError **error);
char * g_data_input_stream_read_until (GDataInputStream *stream,
- const gchar *stop_chars,
- gsize *length,
- GCancellable *cancellable,
- GError **error);
+ const gchar *stop_chars,
+ gsize *length,
+ GCancellable *cancellable,
+ GError **error);
void g_data_input_stream_read_until_async (GDataInputStream *stream,
- const gchar *stop_chars,
+ const gchar *stop_chars,
gint io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -127,6 +127,24 @@ char * g_data_input_stream_read_until_finish (GDataInputStrea
gsize *length,
GError **error);
+char * g_data_input_stream_read_upto (GDataInputStream *stream,
+ const gchar *stop_chars,
+ gssize stop_chars_len,
+ gsize *length,
+ GCancellable *cancellable,
+ GError **error);
+void g_data_input_stream_read_upto_async (GDataInputStream *stream,
+ const gchar *stop_chars,
+ gssize stop_chars_len,
+ gint io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+char * g_data_input_stream_read_upto_finish (GDataInputStream *stream,
+ GAsyncResult *result,
+ gsize *length,
+ GError **error);
+
G_END_DECLS
#endif /* __G_DATA_INPUT_STREAM_H__ */
diff --git a/gio/gio.symbols b/gio/gio.symbols
index fa5d623..0e33f61 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -247,6 +247,9 @@ g_data_input_stream_read_line_finish
g_data_input_stream_read_until
g_data_input_stream_read_until_async
g_data_input_stream_read_until_finish
+g_data_input_stream_read_upto
+g_data_input_stream_read_upto_async
+g_data_input_stream_read_upto_finish
#endif
#endif
diff --git a/gio/tests/data-input-stream.c b/gio/tests/data-input-stream.c
index bc9e4ea..1a34205 100644
--- a/gio/tests/data-input-stream.c
+++ b/gio/tests/data-input-stream.c
@@ -164,7 +164,8 @@ test_read_until (void)
#define DATA_STRING " part1 # part2 $ part3 % part4 ^"
#define DATA_PART_LEN 7 /* number of characters between separators */
#define DATA_SEP "#$%^"
- const int DATA_PARTS_NUM = strlen (DATA_SEP) * REPEATS;
+#define DATA_SEP_LEN 4
+ const int DATA_PARTS_NUM = DATA_SEP_LEN * REPEATS;
base_stream = g_memory_input_stream_new ();
stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream));
@@ -190,12 +191,65 @@ test_read_until (void)
}
g_assert_no_error (error);
g_assert_cmpint (line, ==, DATA_PARTS_NUM);
-
-
+
g_object_unref (base_stream);
g_object_unref (stream);
}
+static void
+test_read_upto (void)
+{
+ GInputStream *stream;
+ GInputStream *base_stream;
+ GError *error = NULL;
+ char *data;
+ int line;
+ int i;
+ guchar stop_char;
+
+#undef REPEATS
+#undef DATA_STRING
+#undef DATA_PART_LEN
+#undef DATA_SEP
+#undef DATA_SEP_LEN
+#define REPEATS 10 /* number of rounds */
+#define DATA_STRING " part1 # part2 $ part3 \0 part4 ^"
+#define DATA_PART_LEN 7 /* number of characters between separators */
+#define DATA_SEP "#$\0^"
+#define DATA_SEP_LEN 4
+ const int DATA_PARTS_NUM = DATA_SEP_LEN * REPEATS;
+
+ base_stream = g_memory_input_stream_new ();
+ stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream));
+
+ for (i = 0; i < REPEATS; i++)
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), DATA_STRING, 32, NULL);
+
+ /* Test stop characters */
+ error = NULL;
+ data = (char*)1;
+ line = 0;
+ while (data)
+ {
+ gsize length = -1;
+ data = g_data_input_stream_read_upto (G_DATA_INPUT_STREAM (stream), DATA_SEP, DATA_SEP_LEN, &length, NULL, &error);
+ if (data)
+ {
+ g_assert_cmpint (strlen (data), ==, DATA_PART_LEN);
+ g_assert_no_error (error);
+ line++;
+
+ stop_char = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (stream), NULL, &error);
+ g_assert (memchr (DATA_SEP, stop_char, DATA_SEP_LEN) != NULL);
+ g_assert_no_error (error);
+ }
+ }
+ g_assert_no_error (error);
+ g_assert_cmpint (line, ==, DATA_PARTS_NUM);
+
+ g_object_unref (base_stream);
+ g_object_unref (stream);
+}
enum TestDataType {
TEST_DATA_BYTE = 0,
TEST_DATA_INT16,
@@ -367,6 +421,7 @@ main (int argc,
g_test_add_func ("/data-input-stream/read-lines-CR-LF", test_read_lines_CR_LF);
g_test_add_func ("/data-input-stream/read-lines-any", test_read_lines_any);
g_test_add_func ("/data-input-stream/read-until", test_read_until);
+ g_test_add_func ("/data-input-stream/read-upto", test_read_upto);
g_test_add_func ("/data-input-stream/read-int", test_read_int);
return g_test_run();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]