Add cfw_stream_read_line().

This also adds a caching infrastructure to cfw_stream.
This commit is contained in:
Jonathan Schleifer 2012-09-30 03:01:37 +02:00
parent 8f0ffd2483
commit 977f3a0a44
4 changed files with 189 additions and 7 deletions

View file

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

View file

@ -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);
} }

View file

@ -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*);

View file

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