forked from lda/telodendria
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.
This commit is contained in:
parent
92da3542a6
commit
ab4755240a
4 changed files with 115 additions and 10 deletions
44
src/Io.c
44
src/Io.c
|
@ -5,8 +5,8 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
75
src/Stream.c
75
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 <Io.h>
|
||||
#include <Memory.h>
|
||||
#include <Util.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -40,4 +40,7 @@ StreamClearError(Stream *);
|
|||
extern int
|
||||
StreamFlush(Stream *);
|
||||
|
||||
extern ssize_t
|
||||
StreamCopy(Stream *, Stream *);
|
||||
|
||||
#endif /* TELODENDRIA_STREAM_H */
|
||||
|
|
Loading…
Reference in a new issue