From ab4755240a76d9bf57809d53c87548345cf326df Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 15 Mar 2023 17:14:16 +0000 Subject: [PATCH] Add IoCopy() and StreamCopy() Both do buffered reads and writes, but IoCopy() uses IoRead() and IoWrite() directly, whereas StreamCopy() relies on StreamGetc() and StreamPutc(), which manipulate the stream buffers. --- src/Io.c | 44 +++++++++++++++++++++++--- src/Stream.c | 75 +++++++++++++++++++++++++++++++++++++++++--- src/include/Io.h | 3 ++ src/include/Stream.h | 3 ++ 4 files changed, 115 insertions(+), 10 deletions(-) diff --git a/src/Io.c b/src/Io.c index c261e5e..7f1038a 100644 --- a/src/Io.c +++ b/src/Io.c @@ -5,8 +5,8 @@ #include #include -#ifndef IO_PRINTF_BUFFER -#define IO_PRINTF_BUFFER 1024 +#ifndef IO_BUFFER +#define IO_BUFFER 4096 #endif struct Io @@ -177,13 +177,13 @@ IoVprintf(Io *io, const char *fmt, va_list ap) return -1; } - buf = Malloc(IO_PRINTF_BUFFER); + buf = Malloc(IO_BUFFER); if (!buf) { return -1; } - write = vsnprintf(buf, IO_PRINTF_BUFFER, fmt, ap); + write = vsnprintf(buf, IO_BUFFER, fmt, ap); if (write < 0) { @@ -195,7 +195,7 @@ IoVprintf(Io *io, const char *fmt, va_list ap) * be rare, but may occasionally happen. If it does, realloc to * the correct size and try again. */ - if (write >= IO_PRINTF_BUFFER) + if (write >= IO_BUFFER) { char *new = Realloc(buf, write + 1); if (!new) @@ -228,3 +228,37 @@ IoPrintf(Io *io, const char *fmt, ...) return ret; } + +ssize_t +IoCopy(Io *in, Io *out) +{ + ssize_t nBytes = 0; + char buf[IO_BUFFER]; + ssize_t rRes; + ssize_t wRes; + + if (!in || !out) + { + errno = EBADF; + return -1; + } + + while ((rRes = IoRead(in, &buf, IO_BUFFER)) != 0) + { + if (rRes == -1) + { + return -1; + } + + wRes = IoWrite(out, &buf, rRes); + + if (wRes == -1) + { + return -1; + } + + nBytes += wRes; + } + + return nBytes; +} diff --git a/src/Stream.c b/src/Stream.c index 491f21e..19801b9 100644 --- a/src/Stream.c +++ b/src/Stream.c @@ -4,11 +4,20 @@ #define STREAM_BUFFER 4096 #endif +#ifndef STREAM_RETRIES +#define STREAM_RETRIES 10 +#endif + +#ifndef STREAM_DELAY +#define STREAM_DELAY 2 +#endif + #define STREAM_EOF (1 << 0) #define STREAM_ERR (1 << 1) #include #include +#include #include #include @@ -29,7 +38,7 @@ struct Stream size_t ugSize; size_t ugLen; - int flags : 2; + int flags:2; }; Stream * @@ -55,7 +64,7 @@ StreamOpen(Io * io) } int -StreamClose(Stream *stream) +StreamClose(Stream * stream) { int ret = 0; @@ -73,6 +82,7 @@ StreamClose(Stream *stream) if (stream->wBuf) { ssize_t writeRes = IoWrite(stream->io, stream->wBuf, stream->wLen); + Free(stream->wBuf); if (writeRes == -1) @@ -100,12 +110,12 @@ StreamVprintf(Stream * stream, const char *fmt, va_list ap) return -1; } - StreamFlush(stream); /* Flush the buffer out before doing the printf */ + StreamFlush(stream); /* Flush the buffer out before doing + * the printf */ /* Defer printf to underlying Io. We probably should buffer the * printf operation just like StreamPutc() so we don't have to - * flush the buffer. - */ + * flush the buffer. */ return IoVprintf(stream->io, fmt, ap); } @@ -317,3 +327,58 @@ StreamFlush(Stream * stream) return 0; } + +ssize_t +StreamCopy(Stream * in, Stream * out) +{ + ssize_t nBytes = 0; + int c; + int tries = 0; + int readFlg = 0; + + while (1) + { + c = StreamGetc(in); + + if (StreamEof(in)) + { + break; + } + + if (StreamError(in)) + { + if (errno == EAGAIN) + { + StreamClearError(in); + tries++; + + if (tries >= STREAM_RETRIES || readFlg) + { + break; + } + else + { + UtilSleepMillis(STREAM_DELAY); + continue; + } + } + else + { + break; + } + } + + /* As soon as we've successfully read a byte, treat future + * EAGAINs as EOF, because somebody might have forgotten to + * close their stream. */ + + readFlg = 1; + tries = 0; + + StreamPutc(out, c); + nBytes++; + } + + StreamFlush(out); + return nBytes; +} diff --git a/src/include/Io.h b/src/include/Io.h index 7d822a4..ff86675 100644 --- a/src/include/Io.h +++ b/src/include/Io.h @@ -43,4 +43,7 @@ IoVprintf(Io *, const char *, va_list); extern int IoPrintf(Io *, const char *, ...); +extern ssize_t +IoCopy(Io *, Io *); + #endif /* TELODENDRIA_IO_H */ diff --git a/src/include/Stream.h b/src/include/Stream.h index d3cfbac..ef94f52 100644 --- a/src/include/Stream.h +++ b/src/include/Stream.h @@ -40,4 +40,7 @@ StreamClearError(Stream *); extern int StreamFlush(Stream *); +extern ssize_t +StreamCopy(Stream *, Stream *); + #endif /* TELODENDRIA_STREAM_H */