dovecot-2.2: lib: Added istream-callback API
dovecot at dovecot.org
dovecot at dovecot.org
Mon Aug 11 14:45:32 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/1b76af8a8ded
changeset: 17701:1b76af8a8ded
user: Timo Sirainen <tss at iki.fi>
date: Mon Aug 11 17:43:25 2014 +0300
description:
lib: Added istream-callback API
diffstat:
src/lib/Makefile.am | 2 +
src/lib/istream-callback.c | 107 +++++++++++++++++++++++++++++++++++++++++++++
src/lib/istream-callback.h | 35 ++++++++++++++
3 files changed, 144 insertions(+), 0 deletions(-)
diffs (169 lines):
diff -r 2ce864f0176a -r 1b76af8a8ded src/lib/Makefile.am
--- a/src/lib/Makefile.am Mon Aug 11 16:08:44 2014 +0300
+++ b/src/lib/Makefile.am Mon Aug 11 17:43:25 2014 +0300
@@ -58,6 +58,7 @@
istream.c \
istream-base64-decoder.c \
istream-base64-encoder.c \
+ istream-callback.c \
istream-chain.c \
istream-concat.c \
istream-crlf.c \
@@ -191,6 +192,7 @@
iso8601-date.h \
istream.h \
istream-base64.h \
+ istream-callback.h \
istream-chain.h \
istream-concat.h \
istream-crlf.h \
diff -r 2ce864f0176a -r 1b76af8a8ded src/lib/istream-callback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-callback.c Mon Aug 11 17:43:25 2014 +0300
@@ -0,0 +1,107 @@
+/* Copyright (c) 2014 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "istream-private.h"
+#include "istream-callback.h"
+
+struct callback_istream {
+ struct istream_private istream;
+ istream_callback_read_t *callback;
+ void *context;
+
+ buffer_t *buf;
+ size_t pending_size;
+};
+
+static void i_stream_callback_destroy(struct iostream_private *stream)
+{
+ struct callback_istream *cstream = (struct callback_istream *)stream;
+
+ buffer_free(&cstream->buf);
+}
+
+static ssize_t i_stream_callback_read(struct istream_private *stream)
+{
+ struct callback_istream *cstream = (struct callback_istream *)stream;
+ size_t pos;
+
+ if (cstream->callback == NULL) {
+ /* already returned EOF / error */
+ stream->istream.eof = TRUE;
+ return -1;
+ }
+
+ if (stream->skip > 0) {
+ buffer_delete(cstream->buf, 0, stream->skip);
+ stream->pos -= stream->skip;
+ stream->skip = 0;
+ }
+ pos = cstream->buf->used;
+ if (cstream->pending_size > 0) {
+ i_assert(pos >= cstream->pending_size);
+ pos -= cstream->pending_size;
+ cstream->pending_size = 0;
+ } else if (!cstream->callback(cstream->buf, cstream->context)) {
+ /* EOF / error */
+ stream->istream.eof = TRUE;
+ cstream->callback = NULL;
+ if (cstream->buf->used == pos ||
+ stream->istream.stream_errno != 0)
+ return -1;
+ /* EOF was returned with some data still added to the buffer.
+ return the buffer first and EOF only on the next call. */
+ } else if (cstream->buf->used == pos) {
+ /* buffer full */
+ i_assert(cstream->buf->used > 0);
+ return -2;
+ }
+ i_assert(cstream->buf->used > pos);
+ stream->buffer = cstream->buf->data;
+ stream->pos = cstream->buf->used;
+ return cstream->buf->used - pos;
+}
+
+#undef i_stream_create_callback
+struct istream *
+i_stream_create_callback(istream_callback_read_t *callback, void *context)
+{
+ struct callback_istream *cstream;
+ struct istream *istream;
+
+ i_assert(callback != NULL);
+
+ cstream = i_new(struct callback_istream, 1);
+ cstream->callback = callback;
+ cstream->context = context;
+ cstream->buf = buffer_create_dynamic(default_pool, 1024);
+
+ cstream->istream.iostream.destroy = i_stream_callback_destroy;
+ cstream->istream.read = i_stream_callback_read;
+
+ istream = i_stream_create(&cstream->istream, NULL, -1);
+ istream->blocking = TRUE;
+ return istream;
+}
+
+void i_stream_callback_append(struct istream *input,
+ const void *data, size_t size)
+{
+ struct callback_istream *cstream =
+ (struct callback_istream *)input->real_stream;
+
+ buffer_append(cstream->buf, data, size);
+ cstream->pending_size += size;
+}
+
+void i_stream_callback_append_str(struct istream *input, const char *str)
+{
+ i_stream_callback_append(input, str, strlen(str));
+}
+
+void i_stream_callback_set_error(struct istream *input, int stream_errno,
+ const char *error)
+{
+ input->stream_errno = stream_errno;
+ io_stream_set_error(&input->real_stream->iostream, "%s", error);
+}
diff -r 2ce864f0176a -r 1b76af8a8ded src/lib/istream-callback.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/istream-callback.h Mon Aug 11 17:43:25 2014 +0300
@@ -0,0 +1,35 @@
+#ifndef ISTREAM_CALLBACK_H
+#define ISTREAM_CALLBACK_H
+
+/* istream-callback can be used to implement an istream that returns data
+ by calling the specified callback. The callback needs to do:
+
+ a) Add data to buffer unless the buffer size is already too large
+ (the callback can decide by itself what is too large). Return TRUE
+ regardless of whether any data was added.
+
+ b) Return FALSE when it's finished adding data or when it reaches an error.
+ On error i_stream_callback_set_error() must be called before returning.
+
+ i_stream_add_destroy_callback() can be also added to do any cleanups that
+ the callback may need to do.
+*/
+typedef bool istream_callback_read_t(buffer_t *buf, void *context);
+
+struct istream *
+i_stream_create_callback(istream_callback_read_t *callback, void *context);
+#define i_stream_create_callback(callback, context) \
+ i_stream_create_callback(1 ? (istream_callback_read_t *)callback : \
+ CALLBACK_TYPECHECK(callback, bool (*)(buffer_t *buf, typeof(context))), \
+ context)
+
+/* Append data to the istream externally. Typically this is used to add a
+ header to the stream before the callbacks are called. */
+void i_stream_callback_append(struct istream *input,
+ const void *data, size_t size);
+void i_stream_callback_append_str(struct istream *input, const char *str);
+
+void i_stream_callback_set_error(struct istream *input, int stream_errno,
+ const char *error);
+
+#endif
More information about the dovecot-cvs
mailing list