Begin prototyping Stream API.

This commit is contained in:
Jordan Bancino 2023-03-15 02:40:23 +00:00
parent ae97d8116c
commit afc7667737
3 changed files with 248 additions and 3 deletions

View file

@ -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

170
src/Stream.c Normal file
View file

@ -0,0 +1,170 @@
#include <Stream.h>
#include <Memory.h>
#include <errno.h>
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);
}

73
src/include/Stream.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef TELODENDRIA_STREAM_H
#define TELODENDRIA_STREAM_H
#include <unistd.h>
#include <stdarg.h>
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 */