diff options
-rw-r--r-- | stream.c | 133 |
1 files changed, 85 insertions, 48 deletions
@@ -110,7 +110,84 @@ int stream_read(lua_State * L) return stream_readk(L, LUA_OK, (lua_KContext) s); // Intentionally do not remove arguments from the stack. } -static int until(struct buffer * b, const char * pattern, const int pattern_length) +static int grow(lua_State *, struct buffer *); +static int prepare_at_least(lua_State *, struct stream *, const int); +static int read_more(lua_State *, struct stream *, const int); +static int until(struct buffer *, const char *, const int); + +static int grow(lua_State * L, struct buffer * b) +{ + int allocated = b->allocated + 1024; + + if (8192 < allocated) + { + lua_pushliteral(L, "Too large buffer"); + return lua_error(L); + } + + void * buffer = realloc(b->data, allocated); + + if (NULL == buffer) + { + lua_pushliteral(L, "Could not grow buffer"); + return lua_error(L); + } + + b->data = buffer; + b->allocated = allocated; + + return 0; +} + +static int read_more(lua_State * L, struct stream * s, int minimum_length) +{ + const int free_space = s->in.allocated + s->in.offset - s->in.length - 1; + + while (free_space < minimum_length) + { + grow(L, &s->in); + } + + if (0 < s->in.offset) + { + memmove(s->in.data, s->in.data + s->in.offset, s->in.length - s->in.offset); + s->in.offset = 0; + s->in.length -= s->in.offset; + } + + int length = read(s->fd, s->in.data + s->in.length, free_space); + + if (-1 == length) + { + if (EWOULDBLOCK == errno || EAGAIN == errno) + { + return lua_yieldk(L, 0, (lua_KContext) s, stream_readk); + } + else + { + lua_pushstring(L, strerror(errno)); + return lua_error(L); + } + } + + s->in.length += length; + + return length; +} + +static int prepare_at_least(lua_State * L, struct stream * s, int minimum_length) +{ + const int remaining_bytes = s->in.length - s->in.offset; + + if (remaining_bytes < minimum_length) + { + return read_more(L, s, minimum_length); + } + + return 0; +} + +static int until(struct buffer * b, const char * pattern, int pattern_length) { int offset = b->offset; @@ -138,58 +215,18 @@ int stream_readk(lua_State * L, int status, lua_KContext ctx) { struct stream * s = (struct stream *) ctx; - int remaining_bytes = s->in.length - s->in.offset; - int offset = -1; - - size_t len; - const char * pattern = lua_tolstring(L, 2, &len); - const int pattern_length = (int) len; + size_t pattern_length; + const char * pattern = lua_tolstring(L, 2, &pattern_length); // TODO: NULL check - if (pattern_length <= remaining_bytes) + int offset; + do { - offset = until(&s->in, pattern, pattern_length); - } - - if (-1 == offset || 0 == remaining_bytes) - { - if (0 < s->in.length && 0 <= s->in.allocated - s->in.offset - 1) - { - // TODO: Allow buffer to grow some before raising an error. - lua_pushliteral(L, "Read buffer growing not implemented"); - return lua_error(L); - } - - // TODO: Allow user to control amount of bytes being read. - int length = read(s->fd, s->in.data + s->in.offset, s->in.allocated - s->in.offset - 1); - - if (-1 == length) - { - if (EWOULDBLOCK == errno || EAGAIN == errno) - { - return lua_yieldk(L, 0, ctx, stream_readk); - } - else - { - lua_pop(L, 1); - lua_pushstring(L, strerror(errno)); - return lua_error(L); - } - } - - s->in.data[length] = 0; - s->in.length = s->in.offset + length; - - offset = until(&s->in, pattern, pattern_length); - - if (-1 == offset) - { - // TODO: Reiterate at this point, grow buffer until some error is reached or pattern is found. - lua_pushliteral(L, "Could not find pattern"); - return lua_error(L); - } + prepare_at_least(L, s, (int) pattern_length); + offset = until(&s->in, pattern, (int) pattern_length); } + while (-1 == offset); lua_pushlstring(L, &s->in.data[s->in.offset], offset - s->in.offset); s->in.offset = offset + 1; |