diff --git a/TODO.txt b/TODO.txt index d71c644..95377ba 100644 --- a/TODO.txt +++ b/TODO.txt @@ -11,11 +11,13 @@ Key: Milestone: v0.3.0 ----------------- -[ ] Stream API +[~] Stream API + [~] Implementation + [ ] Convert all HTTP code and JSON code + [ ] Multi-output (proof of concept) [ ] TLS [ ] SOCKS - [ ] Multi-output - [ ] Move UtilStreamCopy() + [ ] Move/convert UtilStreamCopy() [~] HTTP Client API [x] Document HttpParseHeaders() [ ] HttpClient man page diff --git a/src/Stream.c b/src/Stream.c new file mode 100644 index 0000000..d6afbb8 --- /dev/null +++ b/src/Stream.c @@ -0,0 +1,170 @@ +#include + +#include + +#include + +struct Stream +{ + StreamFunctions io; + void *cookie; + + int *ub; + size_t ubSize; + size_t ubLen; +}; + +Stream * +StreamCreate(void *cookie, StreamFunctions funcs) +{ + Stream *stream; + + if (!funcs.read || !funcs.write) + { + return NULL; + } + + stream = Malloc(sizeof(Stream)); + + if (!stream) + { + return NULL; + } + + stream->cookie = cookie; + + 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; +} + +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 +StreamClose(Stream *stream) +{ + int ret; + + if (!stream) + { + errno = EBADF; + return -1; + } + + if (stream->io.close) + { + ret = stream->io.close(stream->cookie); + } + else + { + ret = 0; + } + + if (stream->ubSize) + { + Free(stream->ub); + } + + Free(stream); + + return ret; +} + +static ssize_t +StreamReadFd(void *cookie, void *buf, size_t nBytes) +{ + int fd = *((int *) cookie); + + return read(fd, buf, nBytes); +} + +static ssize_t +StreamWriteFd(void *cookie, void *buf, size_t nBytes) +{ + int fd = *((int *) cookie); + + return write(fd, buf, nBytes); +} + +static off_t +StreamSeekFd(void *cookie, off_t offset, int whence) +{ + int fd = *((int *) cookie); + + return lseek(fd, offset, whence); +} + +static int +StreamCloseFd(void *cookie) +{ + int fd = *((int *) cookie); + + return close(fd); +} + +Stream * +StreamOpen(int fd) +{ + int *fdp = Malloc(sizeof(int)); + StreamFunctions f; + + if (!fdp) + { + return NULL; + } + + *fdp = fd; + + f.read = StreamReadFd; + f.write = StreamWriteFd; + f.seek = StreamSeekFd; + f.close = StreamCloseFd; + + return StreamCreate(fdp, f); + +} diff --git a/src/include/Stream.h b/src/include/Stream.h new file mode 100644 index 0000000..3a14ab8 --- /dev/null +++ b/src/include/Stream.h @@ -0,0 +1,73 @@ +#ifndef TELODENDRIA_STREAM_H +#define TELODENDRIA_STREAM_H + +#include +#include + +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 * +StreamCreate(void *, StreamFunctions); + +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 +StreamClose(Stream *); + +extern Stream * +StreamOpen(int); + +/* + * High level Stream API in the style of C standard I/O. + */ + +extern int +StreamVprintf(Stream *, const char *, va_list); + +extern int +StreamPrintf(Stream *, const char *, ...); + +extern int +StreamGetc(Stream *); + +extern int +StreamUngetc(Stream *, int); + +extern int +StreamEof(Stream *); + +extern int +StreamError(Stream *); + +extern void +StreamClearError(Stream *); + +extern int +StreamFlush(Stream *); + +#endif /* TELODENDRIA_STREAM_H */