summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/kit/input_buffer.c73
-rw-r--r--source/kit/input_buffer.h7
-rw-r--r--source/test/unittests/input_buffer.test.c48
3 files changed, 116 insertions, 12 deletions
diff --git a/source/kit/input_buffer.c b/source/kit/input_buffer.c
index b9f280b..8ac7755 100644
--- a/source/kit/input_buffer.c
+++ b/source/kit/input_buffer.c
@@ -98,23 +98,72 @@ kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream,
kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, ptrdiff_t size) {
kit_ib_handle_t next;
memset(&next, 0, sizeof next);
+
if (buf.status != KIT_OK) {
next.status = buf.status;
- } else {
- buf_acquire(buf.internal);
- buf_adjust(buf.internal, buf.offset + size);
- DA_INIT(next.data, size, buf_alloc(buf.internal));
- if (next.data.size != size)
- next.status = KIT_ERROR_BAD_ALLOC;
- kit_out_str_t destination = { .size = next.data.size,
+ return next;
+ }
+
+ buf_acquire(buf.internal);
+ buf_adjust(buf.internal, buf.offset + size);
+
+ DA_INIT(next.data, size, buf_alloc(buf.internal));
+ if (next.data.size != size)
+ next.status = KIT_ERROR_BAD_ALLOC;
+
+ kit_out_str_t destination = { .size = next.data.size,
.values = next.data.values };
- ptrdiff_t n = buf_read(buf.internal, buf.offset, destination);
- next.offset = buf.offset + n;
- next.internal = buf.internal;
- DA_RESIZE(next.data, n);
- if (next.data.size != n)
+ ptrdiff_t const n = buf_read(buf.internal, buf.offset, destination);
+ next.offset = buf.offset + n;
+ next.internal = buf.internal;
+
+ DA_RESIZE(next.data, n);
+ if (next.data.size != n)
+ next.status = KIT_ERROR_BAD_ALLOC;
+
+ return next;
+}
+
+kit_ib_handle_t kit_ib_read_while(
+ kit_ib_handle_t buf, kit_ib_read_condition_fn condition) {
+ kit_ib_handle_t next;
+ memset(&next, 0, sizeof next);
+
+ if (buf.status != KIT_OK) {
+ next.status = buf.status;
+ return next;
+ }
+
+ buf_acquire(buf.internal);
+
+ DA_INIT(next.data, 0, buf_alloc(buf.internal));
+
+ ptrdiff_t size = 0;
+
+ for (;; ++size) {
+ buf_adjust(buf.internal, buf.offset + size + 1);
+
+ DA_RESIZE(next.data, size + 1);
+ if (next.data.size != size + 1)
next.status = KIT_ERROR_BAD_ALLOC;
+
+ kit_out_str_t destination = { .size = 1,
+ .values = next.data.values + size };
+ ptrdiff_t const n = buf_read(buf.internal, buf.offset + size,
+ destination);
+
+ kit_str_t data = { .size = size + 1, .values = next.data.values };
+ if (n != 1 || condition == NULL || condition(data) == 0)
+ break;
}
+
+ next.offset = buf.offset + size;
+ next.internal = buf.internal;
+
+ DA_RESIZE(next.data, size);
+ if (next.data.size != size)
+ next.status = KIT_ERROR_BAD_ALLOC;
+
return next;
}
diff --git a/source/kit/input_buffer.h b/source/kit/input_buffer.h
index 1b4329f..60b4872 100644
--- a/source/kit/input_buffer.h
+++ b/source/kit/input_buffer.h
@@ -21,6 +21,11 @@ kit_ib_handle_t kit_ib_wrap(kit_is_handle_t upstream,
kit_ib_handle_t kit_ib_read(kit_ib_handle_t buf, ptrdiff_t size);
+typedef int (*kit_ib_read_condition_fn)(kit_str_t data);
+
+kit_ib_handle_t kit_ib_read_while(kit_ib_handle_t buf,
+ kit_ib_read_condition_fn condition);
+
void kit_ib_destroy(kit_ib_handle_t buf);
#define KIT_IB_WRAP(upstream) \
@@ -28,8 +33,10 @@ void kit_ib_destroy(kit_ib_handle_t buf);
#ifndef KIT_DISABLE_SHORT_NAMES
# define ib_handle_t kit_ib_handle_t
+# define ib_read_condition_fn kit_ib_read_condition_fn
# define ib_wrap kit_ib_wrap
# define ib_read kit_ib_read
+# define ib_read_while kit_ib_read_while
# define ib_destroy kit_ib_destroy
# define IB_WRAP KIT_IB_WRAP
diff --git a/source/test/unittests/input_buffer.test.c b/source/test/unittests/input_buffer.test.c
index f1b3738..c062052 100644
--- a/source/test/unittests/input_buffer.test.c
+++ b/source/test/unittests/input_buffer.test.c
@@ -55,3 +55,51 @@ TEST("input buffer read twice") {
ib_destroy(first);
is_destroy(in);
}
+
+static int is_integer_(str_t const data) {
+ for (ptrdiff_t i = 0; i < data.size; i++)
+ if (data.values[i] < '0' || data.values[i] > '9')
+ return 0;
+ return 1;
+}
+
+TEST("input buffer read integer once") {
+ str_t text = { .size = 9, .values = "31415 foo" };
+ str_t num = { .size = 5, .values = "31415" };
+ is_handle_t in = IS_WRAP_STRING(text);
+ ib_handle_t first = IB_WRAP(in);
+
+ ib_handle_t second = ib_read_while(first, is_integer_);
+
+ REQUIRE(second.status == KIT_OK);
+ REQUIRE(second.data.size == 5);
+ REQUIRE(AR_EQUAL(num, second.data));
+
+ ib_destroy(second);
+ ib_destroy(first);
+ is_destroy(in);
+}
+
+TEST("input buffer read integer twice") {
+ str_t text = { .size = 6, .values = "314 15" };
+ str_t num_0 = { .size = 3, .values = "314" };
+ str_t num_1 = { .size = 2, .values = "15" };
+ is_handle_t in = IS_WRAP_STRING(text);
+ ib_handle_t first = IB_WRAP(in);
+
+ ib_handle_t second = ib_read_while(first, is_integer_);
+ ib_handle_t third = ib_read(second, 1);
+ ib_handle_t fourth = ib_read_while(third, is_integer_);
+
+ REQUIRE(fourth.status == KIT_OK);
+ REQUIRE(second.data.size == 3);
+ REQUIRE(fourth.data.size == 2);
+ REQUIRE(AR_EQUAL(num_0, second.data));
+ REQUIRE(AR_EQUAL(num_1, fourth.data));
+
+ ib_destroy(first);
+ ib_destroy(second);
+ ib_destroy(third);
+ ib_destroy(fourth);
+ is_destroy(in);
+}