summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2002-11-03 12:53:25 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2002-11-03 12:53:25 +0000
commit30c0872d8409df211bc8a567c8b4f23bbdc8f9af (patch)
tree7dd8031f3ac0d0316cb79a103f1b02a73b4365d8
parent21370dbf8bf74a3b02cdb50bf8c2dfef60642244 (diff)
downloadmailutils-30c0872d8409df211bc8a567c8b4f23bbdc8f9af.tar.gz
mailutils-30c0872d8409df211bc8a567c8b4f23bbdc8f9af.tar.bz2
Some applications (e.g. mail.remote)
implicitly rely on the possibility to seek on stdin streams. To provide this functionality: (struct _file_stram): Added cache member. It is a memory stream used to provide seeking capability for stdio streams. (_file_destroy): Destroy cache if necessary. (_stdin_file_read,_stdin_file_readline,_stdout_file_write): New functions. Provide IO operations for stdio streams. (stdio_stream_create): Register new IO functions.
-rw-r--r--mailbox/file_stream.c111
1 files changed, 108 insertions, 3 deletions
diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c
index 8fc9014a9..3a09bf6d8 100644
--- a/mailbox/file_stream.c
+++ b/mailbox/file_stream.c
@@ -39,6 +39,7 @@ struct _file_stream
int offset;
char *filename;
+ stream_t cache;
};
static void
@@ -51,6 +52,8 @@ _file_destroy (stream_t stream)
if (fs->filename)
free (fs->filename);
+ if (fs->cache)
+ stream_destroy (&fs->cache, stream_get_owner (fs->cache));
free (fs);
}
@@ -173,6 +176,100 @@ _file_write (stream_t stream, const char *iptr, size_t isize,
}
static int
+_stdin_file_read (stream_t stream, char *optr, size_t osize,
+ off_t offset, size_t *pnbytes)
+{
+ int status;
+ size_t nbytes;
+ struct _file_stream *fs = stream_get_owner (stream);
+ int fs_offset = fs->offset;
+
+ if (offset < fs_offset)
+ return stream_read (fs->cache, optr, osize, offset, pnbytes);
+ else if (offset > fs_offset)
+ {
+ int status;
+ size_t n, left = offset - fs_offset + 1;
+ char *buf = malloc (left);
+ if (!buf)
+ return ENOMEM;
+ while (left > 0
+ && (status = stream_read (stream, buf, left, fs_offset, &n)) == 0
+ && n > 0)
+ {
+ size_t k;
+ status = stream_write (fs->cache, buf, n, fs_offset, &k);
+ if (status)
+ break;
+ if (k != n)
+ {
+ status = EIO;
+ break;
+ }
+
+ fs_offset += n;
+ left -= n;
+ }
+ free (buf);
+ if (status)
+ return status;
+ }
+ status = _file_read (stream, optr, osize, fs_offset, &nbytes);
+ if (status == 0 && nbytes)
+ {
+ size_t k;
+
+ status = stream_write (fs->cache, optr, nbytes, fs_offset, &k);
+ if (status)
+ return status;
+ if (k != nbytes)
+ return EIO;
+ }
+ if (pnbytes)
+ *pnbytes = nbytes;
+ return status;
+}
+
+static int
+_stdin_file_readline (stream_t stream, char *optr, size_t osize,
+ off_t offset, size_t *pnbytes)
+{
+ int status;
+ size_t nbytes;
+ struct _file_stream *fs = stream_get_owner (stream);
+ int fs_offset = fs->offset;
+
+ if (offset < fs->offset)
+ return stream_readline (fs->cache, optr, osize, offset, pnbytes);
+ else if (offset > fs->offset)
+ return ESPIPE;
+
+ fs_offset = fs->offset;
+ status = _file_readline (stream, optr, osize, fs_offset, &nbytes);
+ if (status == 0)
+ {
+ size_t k;
+
+ status = stream_write (fs->cache, optr, nbytes, fs_offset, &k);
+ if (status)
+ return status;
+ if (k != nbytes)
+ return EIO;
+ }
+ if (pnbytes)
+ *pnbytes = nbytes;
+ return status;
+}
+
+static int
+_stdout_file_write (stream_t stream, const char *iptr, size_t isize,
+ off_t offset, size_t *nbytes)
+{
+ struct _file_stream *fs = stream_get_owner (stream);
+ return _file_write (stream, iptr, isize, fs->offset, nbytes);
+}
+
+static int
_file_truncate (stream_t stream, off_t len)
{
struct _file_stream *fs = stream_get_owner (stream);
@@ -426,14 +523,22 @@ stdio_stream_create (stream_t *stream, FILE* file, int flags)
return ret;
}
+ if ((ret = memory_stream_create (&fs->cache, 0, MU_STREAM_RDWR))
+ || (ret = stream_open (fs->cache)))
+ {
+ stream_destroy (stream, fs);
+ free (fs);
+ return ret;
+ }
+
/* We don't need to open the FILE, just return success. */
stream_set_open (*stream, NULL, fs);
stream_set_close (*stream, _file_close, fs);
stream_set_fd (*stream, _file_get_fd, fs);
- stream_set_read (*stream, _file_read, fs);
- stream_set_readline (*stream, _file_readline, fs);
- stream_set_write (*stream, _file_write, fs);
+ stream_set_read (*stream, _stdin_file_read, fs);
+ stream_set_readline (*stream, _stdin_file_readline, fs);
+ stream_set_write (*stream, _stdout_file_write, fs);
stream_set_flush (*stream, _file_flush, fs);
stream_set_destroy (*stream, _file_destroy, fs);

Return to:

Send suggestions and report system problems to the System administrator.