diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-05-02 17:58:01 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2010-05-02 18:02:25 +0300 |
commit | b000617bad12dc7d3b0ea5f4541cc66b64e2fb02 (patch) | |
tree | 52e313be38daf359032c2c755ad591b94ab5cff1 | |
parent | 55e8650184dc3f03e98cd41714115dc9803610cc (diff) | |
download | mailutils-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.c | 18 | ||||
-rw-r--r-- | include/mailutils/stream.h | 3 | ||||
-rw-r--r-- | mailbox/fltstream.c | 11 | ||||
-rw-r--r-- | mailbox/stream.c | 65 |
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) |