forked from lda/telodendria
Move low-level fopencookie()/funopen() functionality to Io API.
The Stream API now provides the buffered I/O functionality analogous to the C standard library.
This commit is contained in:
parent
5dbaf3c223
commit
92da3542a6
4 changed files with 546 additions and 151 deletions
230
src/Io.c
Normal file
230
src/Io.c
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
#include <Io.h>
|
||||||
|
|
||||||
|
#include <Memory.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef IO_PRINTF_BUFFER
|
||||||
|
#define IO_PRINTF_BUFFER 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Io
|
||||||
|
{
|
||||||
|
IoFunctions io;
|
||||||
|
void *cookie;
|
||||||
|
};
|
||||||
|
|
||||||
|
Io *
|
||||||
|
IoCreate(void *cookie, IoFunctions funcs)
|
||||||
|
{
|
||||||
|
Io *io;
|
||||||
|
|
||||||
|
/* Must have at least read or write */
|
||||||
|
if (!funcs.read && !funcs.write)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
io = Malloc(sizeof(Io));
|
||||||
|
|
||||||
|
if (!io)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
io->cookie = cookie;
|
||||||
|
|
||||||
|
io->io.read = funcs.read;
|
||||||
|
io->io.write = funcs.write;
|
||||||
|
io->io.seek = funcs.seek;
|
||||||
|
io->io.close = funcs.close;
|
||||||
|
|
||||||
|
return io;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
IoRead(Io *io, void *buf, size_t nBytes)
|
||||||
|
{
|
||||||
|
if (!io || !io->io.read)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return io->io.read(io->cookie, buf, nBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
IoWrite(Io *io, void *buf, size_t nBytes)
|
||||||
|
{
|
||||||
|
if (!io || !io->io.write)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return io->io.write(io->cookie, buf, nBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t
|
||||||
|
IoSeek(Io *io, off_t offset, int whence)
|
||||||
|
{
|
||||||
|
if (!io)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!io->io.seek)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return io->io.seek(io->cookie, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IoClose(Io *io)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!io)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (io->io.close)
|
||||||
|
{
|
||||||
|
ret = io->io.close(io->cookie);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(io);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
IoReadFd(void *cookie, void *buf, size_t nBytes)
|
||||||
|
{
|
||||||
|
int fd = *((int *) cookie);
|
||||||
|
|
||||||
|
return read(fd, buf, nBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
IoWriteFd(void *cookie, void *buf, size_t nBytes)
|
||||||
|
{
|
||||||
|
int fd = *((int *) cookie);
|
||||||
|
|
||||||
|
return write(fd, buf, nBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static off_t
|
||||||
|
IoSeekFd(void *cookie, off_t offset, int whence)
|
||||||
|
{
|
||||||
|
int fd = *((int *) cookie);
|
||||||
|
|
||||||
|
return lseek(fd, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
IoCloseFd(void *cookie)
|
||||||
|
{
|
||||||
|
int fd = *((int *) cookie);
|
||||||
|
|
||||||
|
Free(cookie);
|
||||||
|
return close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Io *
|
||||||
|
IoOpen(int fd)
|
||||||
|
{
|
||||||
|
int *cookie = Malloc(sizeof(int));
|
||||||
|
IoFunctions f;
|
||||||
|
|
||||||
|
if (!cookie)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cookie = fd;
|
||||||
|
|
||||||
|
f.read = IoReadFd;
|
||||||
|
f.write = IoWriteFd;
|
||||||
|
f.seek = IoSeekFd;
|
||||||
|
f.close = IoCloseFd;
|
||||||
|
|
||||||
|
return IoCreate(cookie, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IoVprintf(Io *io, const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
size_t write;
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!io || !fmt)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = Malloc(IO_PRINTF_BUFFER);
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
write = vsnprintf(buf, IO_PRINTF_BUFFER, fmt, ap);
|
||||||
|
|
||||||
|
if (write < 0)
|
||||||
|
{
|
||||||
|
Free(buf);
|
||||||
|
return write;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of bytes to write exceeded buffer size; this should
|
||||||
|
* be rare, but may occasionally happen. If it does, realloc to
|
||||||
|
* the correct size and try again.
|
||||||
|
*/
|
||||||
|
if (write >= IO_PRINTF_BUFFER)
|
||||||
|
{
|
||||||
|
char *new = Realloc(buf, write + 1);
|
||||||
|
if (!new)
|
||||||
|
{
|
||||||
|
Free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = new;
|
||||||
|
|
||||||
|
/* This time we don't care about the return value */
|
||||||
|
vsnprintf(buf, write, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = IoWrite(io, buf, write);
|
||||||
|
|
||||||
|
Free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
IoPrintf(Io *io, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
ret = IoVprintf(io, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
355
src/Stream.c
355
src/Stream.c
|
@ -1,170 +1,319 @@
|
||||||
#include <Stream.h>
|
#include <Stream.h>
|
||||||
|
|
||||||
|
#ifndef STREAM_BUFFER
|
||||||
|
#define STREAM_BUFFER 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STREAM_EOF (1 << 0)
|
||||||
|
#define STREAM_ERR (1 << 1)
|
||||||
|
|
||||||
|
#include <Io.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
struct Stream
|
struct Stream
|
||||||
{
|
{
|
||||||
StreamFunctions io;
|
Io *io;
|
||||||
void *cookie;
|
|
||||||
|
|
||||||
int *ub;
|
int *rBuf;
|
||||||
size_t ubSize;
|
size_t rLen;
|
||||||
size_t ubLen;
|
size_t rOff;
|
||||||
|
|
||||||
|
int *wBuf;
|
||||||
|
size_t wLen;
|
||||||
|
|
||||||
|
int *ugBuf;
|
||||||
|
size_t ugSize;
|
||||||
|
size_t ugLen;
|
||||||
|
|
||||||
|
int flags : 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
Stream *
|
Stream *
|
||||||
StreamCreate(void *cookie, StreamFunctions funcs)
|
StreamOpen(Io * io)
|
||||||
{
|
{
|
||||||
Stream *stream;
|
Stream *stream;
|
||||||
|
|
||||||
if (!funcs.read || !funcs.write)
|
if (!io)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = Malloc(sizeof(Stream));
|
stream = Malloc(sizeof(Stream));
|
||||||
|
|
||||||
if (!stream)
|
if (!stream)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->cookie = cookie;
|
memset(stream, 0, sizeof(Stream));
|
||||||
|
stream->io = io;
|
||||||
stream->io.read = funcs.read;
|
|
||||||
stream->io.write = funcs.write;
|
|
||||||
stream->io.seek = funcs.seek;
|
|
||||||
stream->io.close = funcs.close;
|
|
||||||
|
|
||||||
stream->ubSize = 0;
|
|
||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
|
||||||
StreamRead(Stream *stream, void *buf, size_t nBytes)
|
|
||||||
{
|
|
||||||
if (!stream)
|
|
||||||
{
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream->io.read(stream->cookie, buf, nBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
StreamWrite(Stream *stream, void *buf, size_t nBytes)
|
|
||||||
{
|
|
||||||
if (!stream)
|
|
||||||
{
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream->io.write(stream->cookie, buf, nBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t
|
|
||||||
StreamSeek(Stream *stream, off_t offset, int whence)
|
|
||||||
{
|
|
||||||
if (!stream)
|
|
||||||
{
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stream->io.seek)
|
|
||||||
{
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return stream->io.seek(stream->cookie, offset, whence);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
StreamClose(Stream *stream)
|
StreamClose(Stream *stream)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (!stream)
|
if (!stream)
|
||||||
{
|
{
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -1;
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->io.close)
|
if (stream->rBuf)
|
||||||
{
|
{
|
||||||
ret = stream->io.close(stream->cookie);
|
Free(stream->rBuf);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->ubSize)
|
if (stream->wBuf)
|
||||||
{
|
{
|
||||||
Free(stream->ub);
|
ssize_t writeRes = IoWrite(stream->io, stream->wBuf, stream->wLen);
|
||||||
|
Free(stream->wBuf);
|
||||||
|
|
||||||
|
if (writeRes == -1)
|
||||||
|
{
|
||||||
|
ret = EOF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream->ugBuf)
|
||||||
|
{
|
||||||
|
Free(stream->ugBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = IoClose(stream->io);
|
||||||
Free(stream);
|
Free(stream);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
int
|
||||||
StreamReadFd(void *cookie, void *buf, size_t nBytes)
|
StreamVprintf(Stream * stream, const char *fmt, va_list ap)
|
||||||
{
|
{
|
||||||
int fd = *((int *) cookie);
|
if (!stream)
|
||||||
|
{
|
||||||
return read(fd, buf, nBytes);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
StreamFlush(stream); /* Flush the buffer out before doing the printf */
|
||||||
StreamWriteFd(void *cookie, void *buf, size_t nBytes)
|
|
||||||
{
|
|
||||||
int fd = *((int *) cookie);
|
|
||||||
|
|
||||||
return write(fd, buf, nBytes);
|
/* Defer printf to underlying Io. We probably should buffer the
|
||||||
|
* printf operation just like StreamPutc() so we don't have to
|
||||||
|
* flush the buffer.
|
||||||
|
*/
|
||||||
|
return IoVprintf(stream->io, fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static off_t
|
int
|
||||||
StreamSeekFd(void *cookie, off_t offset, int whence)
|
StreamPrintf(Stream * stream, const char *fmt,...)
|
||||||
{
|
{
|
||||||
int fd = *((int *) cookie);
|
int ret;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
return lseek(fd, offset, whence);
|
va_start(ap, fmt);
|
||||||
|
ret = StreamVprintf(stream, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
int
|
||||||
StreamCloseFd(void *cookie)
|
StreamGetc(Stream * stream)
|
||||||
{
|
{
|
||||||
int fd = *((int *) cookie);
|
int c;
|
||||||
|
|
||||||
return close(fd);
|
if (!stream)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream *
|
/* Empty the ungetc stack first */
|
||||||
StreamOpen(int fd)
|
if (stream->ugLen)
|
||||||
{
|
{
|
||||||
int *fdp = Malloc(sizeof(int));
|
c = stream->ugBuf[stream->ugLen - 1];
|
||||||
StreamFunctions f;
|
stream->ugLen--;
|
||||||
|
return c;
|
||||||
if (!fdp)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*fdp = fd;
|
if (stream->flags & EOF)
|
||||||
|
{
|
||||||
f.read = StreamReadFd;
|
return EOF;
|
||||||
f.write = StreamWriteFd;
|
}
|
||||||
f.seek = StreamSeekFd;
|
|
||||||
f.close = StreamCloseFd;
|
if (!stream->rBuf)
|
||||||
|
{
|
||||||
return StreamCreate(fdp, f);
|
/* No buffer allocated yet */
|
||||||
|
stream->rBuf = Malloc(STREAM_BUFFER * sizeof(int));
|
||||||
|
if (!stream->rBuf)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->rOff = 0;
|
||||||
|
stream->rLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->rOff >= stream->rLen)
|
||||||
|
{
|
||||||
|
/* We read through the entire buffer; get a new one */
|
||||||
|
ssize_t readRes = IoRead(stream->io, stream->rBuf, STREAM_BUFFER);
|
||||||
|
|
||||||
|
if (readRes == 0)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_EOF;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readRes == -1)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->rOff = 0;
|
||||||
|
stream->rLen = readRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the character in the buffer and advance the offset */
|
||||||
|
c = stream->rBuf[stream->rOff];
|
||||||
|
stream->rOff++;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StreamUngetc(Stream * stream, int c)
|
||||||
|
{
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream->ugBuf)
|
||||||
|
{
|
||||||
|
stream->ugSize = STREAM_BUFFER;
|
||||||
|
stream->ugBuf = Malloc(stream->ugSize);
|
||||||
|
|
||||||
|
if (!stream->ugBuf)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->ugLen >= stream->ugSize)
|
||||||
|
{
|
||||||
|
int *new;
|
||||||
|
|
||||||
|
stream->ugSize += STREAM_BUFFER;
|
||||||
|
new = Realloc(stream->ugBuf, stream->ugSize);
|
||||||
|
if (!new)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
Free(stream->ugBuf);
|
||||||
|
stream->ugBuf = NULL;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(stream->ugBuf);
|
||||||
|
stream->ugBuf = new;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->ugBuf[stream->ugLen - 1] = c;
|
||||||
|
stream->ugLen++;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StreamPutc(Stream * stream, int c)
|
||||||
|
{
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream->wBuf)
|
||||||
|
{
|
||||||
|
stream->wBuf = Malloc(STREAM_BUFFER * sizeof(int));
|
||||||
|
if (!stream->wBuf)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->wLen == STREAM_BUFFER)
|
||||||
|
{
|
||||||
|
/* Buffer full; write it */
|
||||||
|
ssize_t writeRes = IoWrite(stream->io, stream->wBuf, stream->wLen);
|
||||||
|
|
||||||
|
if (writeRes == -1)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->wLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->wBuf[stream->wLen] = c;
|
||||||
|
stream->wLen++;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StreamEof(Stream * stream)
|
||||||
|
{
|
||||||
|
return stream && (stream->flags & STREAM_EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StreamError(Stream * stream)
|
||||||
|
{
|
||||||
|
return stream && (stream->flags & STREAM_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
StreamClearError(Stream * stream)
|
||||||
|
{
|
||||||
|
if (stream)
|
||||||
|
{
|
||||||
|
stream->flags &= ~STREAM_ERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
StreamFlush(Stream * stream)
|
||||||
|
{
|
||||||
|
if (!stream)
|
||||||
|
{
|
||||||
|
errno = EBADF;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream->wLen)
|
||||||
|
{
|
||||||
|
ssize_t writeRes = IoWrite(stream->io, stream->wBuf, stream->wLen);
|
||||||
|
|
||||||
|
if (writeRes == -1)
|
||||||
|
{
|
||||||
|
stream->flags |= STREAM_ERR;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->wLen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
46
src/include/Io.h
Normal file
46
src/include/Io.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef TELODENDRIA_IO_H
|
||||||
|
#define TELODENDRIA_IO_H
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
typedef struct Io Io;
|
||||||
|
|
||||||
|
typedef ssize_t (IoReadFunc) (void *, void *, size_t);
|
||||||
|
typedef ssize_t (IoWriteFunc) (void *, void *, size_t);
|
||||||
|
typedef off_t (IoSeekFunc) (void *, off_t, int);
|
||||||
|
typedef int (IoCloseFunc) (void *);
|
||||||
|
|
||||||
|
typedef struct IoFunctions
|
||||||
|
{
|
||||||
|
IoReadFunc *read;
|
||||||
|
IoWriteFunc *write;
|
||||||
|
IoSeekFunc *seek;
|
||||||
|
IoCloseFunc *close;
|
||||||
|
} IoFunctions;
|
||||||
|
|
||||||
|
extern Io *
|
||||||
|
IoCreate(void *, IoFunctions);
|
||||||
|
|
||||||
|
extern ssize_t
|
||||||
|
IoRead(Io *, void *, size_t);
|
||||||
|
|
||||||
|
extern ssize_t
|
||||||
|
IoWrite(Io *, void *, size_t);
|
||||||
|
|
||||||
|
extern off_t
|
||||||
|
IoSeek(Io *, off_t, int);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
IoClose(Io *);
|
||||||
|
|
||||||
|
extern Io *
|
||||||
|
IoOpen(int);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
IoVprintf(Io *, const char *, va_list);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
IoPrintf(Io *, const char *, ...);
|
||||||
|
|
||||||
|
#endif /* TELODENDRIA_IO_H */
|
|
@ -1,51 +1,18 @@
|
||||||
#ifndef TELODENDRIA_STREAM_H
|
#ifndef TELODENDRIA_STREAM_H
|
||||||
#define TELODENDRIA_STREAM_H
|
#define TELODENDRIA_STREAM_H
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <Io.h>
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
typedef struct Stream Stream;
|
typedef struct Stream Stream;
|
||||||
|
|
||||||
/*
|
|
||||||
* Low-level Stream API in the style of POSIX system calls.
|
|
||||||
* Heavily inspired by GNU fopencookie() and BSD funopen().
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef ssize_t (StreamReadFunc) (void *, void *, size_t);
|
|
||||||
typedef ssize_t (StreamWriteFunc) (void *, void *, size_t);
|
|
||||||
typedef off_t (StreamSeekFunc) (void *, off_t, int);
|
|
||||||
typedef int (StreamCloseFunc) (void *);
|
|
||||||
|
|
||||||
typedef struct StreamFunctions
|
|
||||||
{
|
|
||||||
StreamReadFunc *read;
|
|
||||||
StreamWriteFunc *write;
|
|
||||||
StreamSeekFunc *seek;
|
|
||||||
StreamCloseFunc *close;
|
|
||||||
} StreamFunctions;
|
|
||||||
|
|
||||||
extern Stream *
|
extern Stream *
|
||||||
StreamCreate(void *, StreamFunctions);
|
StreamOpen(Io *io);
|
||||||
|
|
||||||
extern ssize_t
|
|
||||||
StreamRead(Stream *, void *, size_t);
|
|
||||||
|
|
||||||
extern ssize_t
|
|
||||||
StreamWrite(Stream *, void *, size_t);
|
|
||||||
|
|
||||||
extern off_t
|
|
||||||
StreamSeek(Stream *, off_t, int);
|
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
StreamClose(Stream *);
|
StreamClose(Stream *);
|
||||||
|
|
||||||
extern Stream *
|
|
||||||
StreamOpen(int);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* High level Stream API in the style of C standard I/O.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
StreamVprintf(Stream *, const char *, va_list);
|
StreamVprintf(Stream *, const char *, va_list);
|
||||||
|
|
||||||
|
@ -58,6 +25,9 @@ StreamGetc(Stream *);
|
||||||
extern int
|
extern int
|
||||||
StreamUngetc(Stream *, int);
|
StreamUngetc(Stream *, int);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
StreamPutc(Stream *, int);
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
StreamEof(Stream *);
|
StreamEof(Stream *);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue