summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2010-05-02 17:58:01 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2010-05-02 18:02:25 +0300
commitb000617bad12dc7d3b0ea5f4541cc66b64e2fb02 (patch)
tree52e313be38daf359032c2c755ad591b94ab5cff1
parent55e8650184dc3f03e98cd41714115dc9803610cc (diff)
downloadmailutils-b000617bad12dc7d3b0ea5f4541cc66b64e2fb02.tar.gz
mailutils-b000617bad12dc7d3b0ea5f4541cc66b64e2fb02.tar.bz2
Implement seek on filters in read-only mode.
* include/mailutils/stream.h (mu_stream_skip_input_bytes): New proto. * mailbox/stream.c (mu_stream_skip_input_bytes): New function. * mailbox/fltstream.c (filter_seek): Re-implement on top of mu_stream_skip_input_bytes. (mu_filter_stream_create): Fix flag validity checking. * examples/base64.c: Add new option (-s) for testing seek operations on filters.
-rw-r--r--examples/base64.c18
-rw-r--r--include/mailutils/stream.h3
-rw-r--r--mailbox/fltstream.c11
-rw-r--r--mailbox/stream.c65
4 files changed, 90 insertions, 7 deletions
diff --git a/examples/base64.c b/examples/base64.c
index 26e87952e..3785a6a0d 100644
--- a/examples/base64.c
+++ b/examples/base64.c
@@ -53,8 +53,9 @@ main (int argc, char * argv [])
int flags = MU_STREAM_READ;
char *input = NULL, *output = NULL;
char *encoding = "base64";
-
- while ((c = getopt (argc, argv, "deE:hi:o:pvw")) != EOF)
+ mu_off_t shift = 0;
+
+ while ((c = getopt (argc, argv, "deE:hi:o:ps:vw")) != EOF)
switch (c)
{
case 'i':
@@ -80,6 +81,10 @@ main (int argc, char * argv [])
case 'p':
printable = 1; /* FIXME: Not implemented */
break;
+
+ case 's':
+ shift = strtoul (optarg, NULL, 0);
+ break;
case 'v':
verbose = 1;
@@ -98,7 +103,7 @@ main (int argc, char * argv [])
}
if (input)
- MU_ASSERT (mu_file_stream_create (&in, input, MU_STREAM_READ));
+ MU_ASSERT (mu_file_stream_create (&in, input, MU_STREAM_READ|MU_STREAM_SEEK));
else
MU_ASSERT (mu_stdio_stream_create (&in, MU_STDIN_FD, 0));
MU_ASSERT (mu_stream_open (in));
@@ -112,13 +117,18 @@ main (int argc, char * argv [])
if (flags == MU_STREAM_READ)
{
- MU_ASSERT (mu_filter_create (&flt, in, encoding, mode, MU_STREAM_READ));
+ MU_ASSERT (mu_filter_create (&flt, in, encoding, mode,
+ MU_STREAM_READ|MU_STREAM_SEEK));
+ if (shift)
+ MU_ASSERT (mu_stream_seek (flt, shift, MU_SEEK_SET, NULL));
c_copy (out, flt);
}
else
{
MU_ASSERT (mu_filter_create (&flt, out, encoding, mode,
MU_STREAM_WRITE));
+ if (shift)
+ MU_ASSERT (mu_stream_seek (in, shift, MU_SEEK_SET, NULL));
c_copy (flt, in);
}
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h
index cdc55e74f..1aee88493 100644
--- a/include/mailutils/stream.h
+++ b/include/mailutils/stream.h
@@ -71,6 +71,9 @@ void mu_stream_clearerr (mu_stream_t stream);
int mu_stream_eof (mu_stream_t stream);
int mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
mu_off_t *pres);
+int mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count,
+ mu_off_t *pres);
+
int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
size_t size);
int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread);
diff --git a/mailbox/fltstream.c b/mailbox/fltstream.c
index 5b1bb1376..99b5a47cc 100644
--- a/mailbox/fltstream.c
+++ b/mailbox/fltstream.c
@@ -313,12 +313,17 @@ filter_wr_flush (mu_stream_t stream)
return rc;
}
-/* FIXME: Seeks in the *transport* stream */
static int
filter_seek (struct _mu_stream *stream, mu_off_t off, mu_off_t *ppos)
{
struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
- return mu_stream_seek (fs->transport, off, MU_SEEK_SET, ppos);
+ int status;
+
+ status = mu_stream_seek (fs->transport, 0, MU_SEEK_SET, NULL);
+ if (status)
+ return status;
+ stream->offset = 0;
+ return mu_stream_skip_input_bytes (stream, off, ppos);
}
static int
@@ -392,7 +397,7 @@ mu_filter_stream_create (mu_stream_t *pflt,
if ((flags & MU_STREAM_RDWR) == MU_STREAM_RDWR
|| !(flags & MU_STREAM_RDWR)
- || (flags & MU_STREAM_SEEK))
+ || (flags & (MU_STREAM_WRITE|MU_STREAM_SEEK)) == (MU_STREAM_WRITE|MU_STREAM_SEEK))
return EINVAL;
fs = (struct _mu_filter_stream *) _mu_stream_create (sizeof (*fs), flags);
diff --git a/mailbox/stream.c b/mailbox/stream.c
index 2cb5ff12e..2bc21179e 100644
--- a/mailbox/stream.c
+++ b/mailbox/stream.c
@@ -334,6 +334,71 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
return 0;
}
+/* Skip COUNT bytes from the current position in stream by reading from
+ it. Return new offset in PRES.
+
+ Return 0 on success, EACCES if STREAM was not opened for reading.
+ Another non-zero exit codes are propagated from the underlying
+ input operations.
+
+ This function is designed to help implement seek method in otherwise
+ unseekable streams (such as filters). Do not use it if you absolutely
+ have to. Using it on an unbuffered stream is a terrible waste of CPU. */
+int
+mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres)
+{
+ mu_off_t pos;
+ int rc;
+
+ if (!(stream->flags & MU_STREAM_READ))
+ return _stream_seterror (stream, EACCES, 1);
+
+ if (stream->buftype == mu_buffer_none)
+ {
+ for (pos = 0; pos < count; pos++)
+ {
+ char c;
+ size_t nrd;
+ rc = mu_stream_read (stream, &c, 1, &nrd);
+ if (nrd == 0)
+ rc = ESPIPE;
+ if (rc)
+ break;
+ }
+ }
+ else
+ {
+ if ((rc = _stream_flush_buffer (stream, 1)))
+ return rc;
+ for (pos = 0;;)
+ {
+ if (stream->level == 0)
+ {
+ rc = _stream_fill_buffer (stream);
+ if (rc)
+ break;
+ if (stream->level == 0)
+ {
+ rc = ESPIPE;
+ break;
+ }
+ }
+ if (pos <= count && count < pos + stream->level)
+ {
+ rc = 0;
+ stream->cur = stream->buffer + count - pos;
+ pos = count;
+ break;
+ }
+ }
+ }
+
+ stream->offset += pos;
+ if (pres)
+ *pres = stream->offset;
+ return rc;
+}
+
int
mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
size_t size)

Return to:

Send suggestions and report system problems to the System administrator.