forked from Telodendria/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 <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#ifndef IO_PRINTF_BUFFER
|
#ifndef IO_BUFFER
|
||||||
#define IO_PRINTF_BUFFER 1024
|
#define IO_BUFFER 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Io
|
struct Io
|
||||||
|
@ -177,13 +177,13 @@ IoVprintf(Io *io, const char *fmt, va_list ap)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = Malloc(IO_PRINTF_BUFFER);
|
buf = Malloc(IO_BUFFER);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
write = vsnprintf(buf, IO_PRINTF_BUFFER, fmt, ap);
|
write = vsnprintf(buf, IO_BUFFER, fmt, ap);
|
||||||
|
|
||||||
if (write < 0)
|
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
|
* be rare, but may occasionally happen. If it does, realloc to
|
||||||
* the correct size and try again.
|
* the correct size and try again.
|
||||||
*/
|
*/
|
||||||
if (write >= IO_PRINTF_BUFFER)
|
if (write >= IO_BUFFER)
|
||||||
{
|
{
|
||||||
char *new = Realloc(buf, write + 1);
|
char *new = Realloc(buf, write + 1);
|
||||||
if (!new)
|
if (!new)
|
||||||
|
@ -228,3 +228,37 @@ IoPrintf(Io *io, const char *fmt, ...)
|
||||||
|
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
71
src/Stream.c
71
src/Stream.c
|
@ -4,11 +4,20 @@
|
||||||
#define STREAM_BUFFER 4096
|
#define STREAM_BUFFER 4096
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef STREAM_RETRIES
|
||||||
|
#define STREAM_RETRIES 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef STREAM_DELAY
|
||||||
|
#define STREAM_DELAY 2
|
||||||
|
#endif
|
||||||
|
|
||||||
#define STREAM_EOF (1 << 0)
|
#define STREAM_EOF (1 << 0)
|
||||||
#define STREAM_ERR (1 << 1)
|
#define STREAM_ERR (1 << 1)
|
||||||
|
|
||||||
#include <Io.h>
|
#include <Io.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -73,6 +82,7 @@ StreamClose(Stream *stream)
|
||||||
if (stream->wBuf)
|
if (stream->wBuf)
|
||||||
{
|
{
|
||||||
ssize_t writeRes = IoWrite(stream->io, stream->wBuf, stream->wLen);
|
ssize_t writeRes = IoWrite(stream->io, stream->wBuf, stream->wLen);
|
||||||
|
|
||||||
Free(stream->wBuf);
|
Free(stream->wBuf);
|
||||||
|
|
||||||
if (writeRes == -1)
|
if (writeRes == -1)
|
||||||
|
@ -100,12 +110,12 @@ StreamVprintf(Stream * stream, const char *fmt, va_list ap)
|
||||||
return -1;
|
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
|
/* Defer printf to underlying Io. We probably should buffer the
|
||||||
* printf operation just like StreamPutc() so we don't have to
|
* printf operation just like StreamPutc() so we don't have to
|
||||||
* flush the buffer.
|
* flush the buffer. */
|
||||||
*/
|
|
||||||
return IoVprintf(stream->io, fmt, ap);
|
return IoVprintf(stream->io, fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,3 +327,58 @@ StreamFlush(Stream * stream)
|
||||||
|
|
||||||
return 0;
|
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
|
extern int
|
||||||
IoPrintf(Io *, const char *, ...);
|
IoPrintf(Io *, const char *, ...);
|
||||||
|
|
||||||
|
extern ssize_t
|
||||||
|
IoCopy(Io *, Io *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_IO_H */
|
#endif /* TELODENDRIA_IO_H */
|
||||||
|
|
|
@ -40,4 +40,7 @@ StreamClearError(Stream *);
|
||||||
extern int
|
extern int
|
||||||
StreamFlush(Stream *);
|
StreamFlush(Stream *);
|
||||||
|
|
||||||
|
extern ssize_t
|
||||||
|
StreamCopy(Stream *, Stream *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_STREAM_H */
|
#endif /* TELODENDRIA_STREAM_H */
|
||||||
|
|
Loading…
Reference in a new issue