Add cfw_stream_read_line().
This also adds a caching infrastructure to cfw_stream.
This commit is contained in:
parent
8f0ffd2483
commit
977f3a0a44
4 changed files with 189 additions and 7 deletions
|
@ -144,8 +144,8 @@ ctor(void *ptr, va_list args)
|
||||||
const char *mode = va_arg(args, const char*);
|
const char *mode = va_arg(args, const char*);
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
/* Make sure we have a valid pointer in case we error out */
|
/* Make sure we have a valid file in case we error out */
|
||||||
file->stream.ops = NULL;
|
cfw_stream->ctor(ptr, args);
|
||||||
file->eof = false;
|
file->eof = false;
|
||||||
|
|
||||||
if ((flags = parse_mode(mode)) == -1)
|
if ((flags = parse_mode(mode)) == -1)
|
||||||
|
@ -162,7 +162,7 @@ ctor(void *ptr, va_list args)
|
||||||
static void
|
static void
|
||||||
dtor(void *ptr)
|
dtor(void *ptr)
|
||||||
{
|
{
|
||||||
cfw_stream_close(ptr);
|
cfw_stream->dtor(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CFWClass class = {
|
static CFWClass class = {
|
||||||
|
|
176
src/stream.c
176
src/stream.c
|
@ -24,16 +24,21 @@
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 4096
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ctor(void *ptr, va_list args)
|
ctor(void *ptr, va_list args)
|
||||||
{
|
{
|
||||||
CFWStream *stream = ptr;
|
CFWStream *stream = ptr;
|
||||||
|
|
||||||
stream->ops = NULL;
|
stream->ops = NULL;
|
||||||
|
stream->cache = NULL;
|
||||||
|
stream->cache_len = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -53,10 +58,178 @@ cfw_stream_read(void *ptr, void *buf, size_t len)
|
||||||
if (stream == NULL || stream->ops == NULL)
|
if (stream == NULL || stream->ops == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (stream->cache == NULL) {
|
||||||
if ((ret = stream->ops->read(stream, buf, len)) < -1)
|
if ((ret = stream->ops->read(stream, buf, len)) < -1)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len >= stream->cache_len) {
|
||||||
|
ret = stream->cache_len;
|
||||||
|
|
||||||
|
memcpy(buf, stream->cache, stream->cache_len);
|
||||||
|
|
||||||
|
free(stream->cache);
|
||||||
|
stream->cache = NULL;
|
||||||
|
stream->cache_len = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
if ((tmp = malloc(stream->cache_len - len)) == NULL)
|
||||||
|
return -1;
|
||||||
|
memcpy(tmp, stream->cache + len, stream->cache_len - len);
|
||||||
|
memcpy(buf, stream->cache, len);
|
||||||
|
|
||||||
|
free(stream->cache);
|
||||||
|
stream->cache = tmp;
|
||||||
|
stream->cache_len -= len;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFWString*
|
||||||
|
cfw_stream_read_line(void *ptr)
|
||||||
|
{
|
||||||
|
CFWStream *stream = ptr;
|
||||||
|
CFWString *ret;
|
||||||
|
char *buf, *ret_str, *new_cache;
|
||||||
|
ssize_t buf_len;
|
||||||
|
size_t i, ret_len;
|
||||||
|
|
||||||
|
/* Look if there is a line or \0 in our cache */
|
||||||
|
if (stream->cache != NULL) {
|
||||||
|
for (i = 0; i < stream->cache_len; i++) {
|
||||||
|
if (stream->cache[i] == '\n' ||
|
||||||
|
stream->cache[i] == '\0') {
|
||||||
|
ret_len = i;
|
||||||
|
if (i > 0 && stream->cache[i - 1] == '\r')
|
||||||
|
ret_len--;
|
||||||
|
|
||||||
|
ret_str = cfw_strndup(stream->cache, ret_len);
|
||||||
|
if (ret_str == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = cfw_create(cfw_string, NULL);
|
||||||
|
if (ret == NULL) {
|
||||||
|
free(ret_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
cfw_string_set_nocopy(ret, ret_str, ret_len);
|
||||||
|
|
||||||
|
new_cache = malloc(stream->cache_len - i - 1);
|
||||||
|
if (new_cache == NULL)
|
||||||
|
return NULL;
|
||||||
|
memcpy(new_cache, stream->cache + i + 1,
|
||||||
|
stream->cache_len - i - 1);
|
||||||
|
|
||||||
|
free(stream->cache);
|
||||||
|
stream->cache = new_cache;
|
||||||
|
stream->cache_len -= i + 1;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and see if we get a newline or \0 */
|
||||||
|
|
||||||
|
if ((buf = malloc(BUFFER_SIZE)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (stream->ops->eof(stream)) {
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (stream->cache == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret_len = stream->cache_len;
|
||||||
|
|
||||||
|
if (ret_len > 0 && stream->cache[ret_len - 1] == '\r')
|
||||||
|
ret_len--;
|
||||||
|
|
||||||
|
ret_str = cfw_strndup(stream->cache, ret_len);
|
||||||
|
if (ret_str == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = cfw_create(cfw_string, NULL);
|
||||||
|
if (ret == NULL) {
|
||||||
|
free(ret_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
cfw_string_set_nocopy(ret, ret_str, ret_len);
|
||||||
|
|
||||||
|
free(stream->cache);
|
||||||
|
stream->cache = NULL;
|
||||||
|
stream->cache_len = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_len = stream->ops->read(stream, buf, BUFFER_SIZE);
|
||||||
|
if (buf_len == -1) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look if there's a newline or \0 */
|
||||||
|
for (i = 0; i < buf_len; i++) {
|
||||||
|
if (buf[i] == '\n' || buf[i] == '\0') {
|
||||||
|
ret_len = stream->cache_len + i;
|
||||||
|
|
||||||
|
if ((ret_str = malloc(ret_len + 1)) == NULL) {
|
||||||
|
/*
|
||||||
|
* FIXME: We lost the current buffer.
|
||||||
|
* Mark the stream as broken?
|
||||||
|
*/
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(ret_str, stream->cache,
|
||||||
|
stream->cache_len);
|
||||||
|
memcpy(ret_str + stream->cache_len, buf, i);
|
||||||
|
if (ret_len > 0 && ret_str[ret_len - 1] == '\r')
|
||||||
|
ret_len--;
|
||||||
|
ret_str[ret_len] = '\0';
|
||||||
|
|
||||||
|
ret = cfw_create(cfw_string, NULL);
|
||||||
|
if (ret == NULL) {
|
||||||
|
free(buf);
|
||||||
|
free(ret_str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
cfw_string_set_nocopy(ret, ret_str, ret_len);
|
||||||
|
|
||||||
|
new_cache = malloc(buf_len - i - 1);
|
||||||
|
if (new_cache == NULL) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(new_cache, buf + i + 1, buf_len - i - 1);
|
||||||
|
|
||||||
|
free(stream->cache);
|
||||||
|
stream->cache = new_cache;
|
||||||
|
stream->cache_len = buf_len - i - 1;
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There was no newline or \0 */
|
||||||
|
new_cache = realloc(stream->cache, stream->cache_len + buf_len);
|
||||||
|
if (new_cache == NULL) {
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(new_cache + stream->cache_len, buf, buf_len);
|
||||||
|
stream->cache = new_cache;
|
||||||
|
stream->cache_len += buf_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -84,6 +257,9 @@ cfw_stream_eof(void *ptr)
|
||||||
if (stream == NULL || stream->ops == NULL)
|
if (stream == NULL || stream->ops == NULL)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (stream->cache != NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
return stream->ops->eof(stream);
|
return stream->ops->eof(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "class.h"
|
#include "class.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
struct cfw_stream_ops {
|
struct cfw_stream_ops {
|
||||||
ssize_t (*read)(void*, void*, size_t);
|
ssize_t (*read)(void*, void*, size_t);
|
||||||
|
@ -42,10 +43,13 @@ struct cfw_stream_ops {
|
||||||
typedef struct CFWStream {
|
typedef struct CFWStream {
|
||||||
CFWObject obj;
|
CFWObject obj;
|
||||||
struct cfw_stream_ops *ops;
|
struct cfw_stream_ops *ops;
|
||||||
|
char *cache;
|
||||||
|
size_t cache_len;
|
||||||
} CFWStream;
|
} CFWStream;
|
||||||
|
|
||||||
extern CFWClass *cfw_stream;
|
extern CFWClass *cfw_stream;
|
||||||
extern ssize_t cfw_stream_read(void*, void*, size_t);
|
extern ssize_t cfw_stream_read(void*, void*, size_t);
|
||||||
|
extern CFWString* cfw_stream_read_line(void*);
|
||||||
extern bool cfw_stream_write(void*, const void*, size_t);
|
extern bool cfw_stream_write(void*, const void*, size_t);
|
||||||
extern bool cfw_stream_write_string(void*, const char*);
|
extern bool cfw_stream_write_string(void*, const char*);
|
||||||
extern bool cfw_stream_eof(void*);
|
extern bool cfw_stream_eof(void*);
|
||||||
|
|
|
@ -96,6 +96,8 @@ ctor(void *ptr, va_list args)
|
||||||
{
|
{
|
||||||
CFWTCPSocket *sock = ptr;
|
CFWTCPSocket *sock = ptr;
|
||||||
|
|
||||||
|
cfw_stream->ctor(ptr, args);
|
||||||
|
|
||||||
sock->fd = -1;
|
sock->fd = -1;
|
||||||
sock->stream.ops = &stream_ops;
|
sock->stream.ops = &stream_ops;
|
||||||
sock->eof = false;
|
sock->eof = false;
|
||||||
|
@ -106,7 +108,7 @@ ctor(void *ptr, va_list args)
|
||||||
static void
|
static void
|
||||||
dtor(void *ptr)
|
dtor(void *ptr)
|
||||||
{
|
{
|
||||||
cfw_stream_close(ptr);
|
cfw_stream->dtor(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue