summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--stream.c133
1 files changed, 85 insertions, 48 deletions
diff --git a/stream.c b/stream.c
index a4fb8c8..c633862 100644
--- a/stream.c
+++ b/stream.c
@@ -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;