summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cbuf.c49
-rw-r--r--cbuf.h31
-rw-r--r--test/test_cbuf.c81
3 files changed, 149 insertions, 12 deletions
diff --git a/cbuf.c b/cbuf.c
index c9c590a..7e7627e 100644
--- a/cbuf.c
+++ b/cbuf.c
@@ -63,16 +63,59 @@ cbuf_update_start(struct cbuf *cbuf)
}
}
-void
-cbuf_push(struct cbuf *cbuf, char byte)
+int
+cbuf_push(struct cbuf *cbuf, const void *buf, size_t size, bool erase)
+{
+ size_t free_size;
+
+ if (!erase) {
+ free_size = cbuf_capacity(cbuf) - cbuf_size(cbuf);
+
+ if (size > free_size) {
+ return ERR_AGAIN;
+ }
+ }
+
+ cbuf_write(cbuf, cbuf_end(cbuf), buf, size);
+ return 0;
+}
+
+int
+cbuf_pop(struct cbuf *cbuf, void *buf, size_t *sizep)
+{
+ int error;
+
+ if (cbuf_size(cbuf) == 0) {
+ return ERR_AGAIN;
+ }
+
+ error = cbuf_read(cbuf, cbuf_start(cbuf), buf, sizep);
+ assert(!error);
+ cbuf->start += *sizep;
+ return 0;
+}
+
+int
+cbuf_pushb(struct cbuf *cbuf, char byte, bool erase)
{
+ size_t free_size;
+
+ if (!erase) {
+ free_size = cbuf_capacity(cbuf) - cbuf_size(cbuf);
+
+ if (free_size == 0) {
+ return ERR_AGAIN;
+ }
+ }
+
cbuf->buf[cbuf_index(cbuf, cbuf->end)] = byte;
cbuf->end++;
cbuf_update_start(cbuf);
+ return 0;
}
int
-cbuf_pop(struct cbuf *cbuf, char *bytep)
+cbuf_popb(struct cbuf *cbuf, char *bytep)
{
if (cbuf_size(cbuf) == 0) {
return ERR_AGAIN;
diff --git a/cbuf.h b/cbuf.h
index 9854082..c5ca8d6 100644
--- a/cbuf.h
+++ b/cbuf.h
@@ -94,12 +94,35 @@ cbuf_range_valid(const struct cbuf *cbuf, size_t start, size_t end)
void cbuf_init(struct cbuf *cbuf, char *buf, size_t capacity);
/*
+ * Append a buffer to a circular buffer.
+ *
+ * If erasing old data is not allowed, and the circular buffer doesn't have
+ * enough unused bytes for the new data, ERR_AGAIN is returned. Otherwise,
+ * the end index is increased by the new data size, possibly erasing old
+ * data, in which case, the start index is updated accordingly.
+ */
+int cbuf_push(struct cbuf *cbuf, const void *buf, size_t size, bool erase);
+
+/*
+ * Read bytes from a circular buffer.
+ *
+ * If the buffer is empty, ERR_AGAIN is returned. Otherwise, the oldest
+ * bytes are stored into the given buffer. On entry, the sizep argument points
+ * to the size of the given buffer. On exit, that value is updated to the
+ * number of bytes actually stored. If successful, the start index is increased
+ * by the amount of bytes read.
+ */
+int cbuf_pop(struct cbuf *cbuf, void *buf, size_t *sizep);
+
+/*
* Append a byte to a circular buffer.
*
- * The end index is incremented. If the buffer is full, the oldest byte
- * is overwritten and the start index is updated accordingly.
+ * If erasing old data is not allowed, and the circular buffer is full,
+ * ERR_AGAIN is returned. Otherwise, the end index is incremented and, if the
+ * buffer is full, the oldest byte is overwritten and the start index
+ * is updated accordingly.
*/
-void cbuf_push(struct cbuf *cbuf, char byte);
+int cbuf_pushb(struct cbuf *cbuf, char byte, bool erase);
/*
* Read a byte from a circular buffer.
@@ -108,7 +131,7 @@ void cbuf_push(struct cbuf *cbuf, char byte);
* byte is stored at the bytep address, the start index is incremented,
* and 0 is returned.
*/
-int cbuf_pop(struct cbuf *cbuf, char *bytep);
+int cbuf_popb(struct cbuf *cbuf, char *bytep);
/*
* Write into a circular buffer at a specific location.
diff --git a/test/test_cbuf.c b/test/test_cbuf.c
index 918597e..15e4d62 100644
--- a/test/test_cbuf.c
+++ b/test/test_cbuf.c
@@ -42,7 +42,7 @@ test_push(struct cbuf *cbuf, const char *s)
len = strlen(s) + 1;
for (i = 0; i < len; i++) {
- cbuf_push(cbuf, s[i]);
+ cbuf_pushb(cbuf, s[i], true);
}
}
@@ -258,12 +258,79 @@ test_write_overflow(void)
#undef STRING
}
-int
-main(int argc, char *argv[])
+static void
+test_push_buf(void)
+{
+ char cbuf_buf[TEST_BUF_SIZE];
+ struct cbuf cbuf;
+ int error;
+
+ cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf));
+
+#define STRING "abcdef"
+ error = cbuf_push(&cbuf, STRING, STRLEN(STRING) + 1, false);
+ check(!error);
+ test_check(&cbuf, cbuf_start(&cbuf), STRING, STRLEN(STRING) + 1);
+ check(cbuf_size(&cbuf) == (STRLEN(STRING) + 1));
+#undef STRING
+}
+
+static void
+test_push_buf_overflow(void)
+{
+ char cbuf_buf[TEST_BUF_SIZE];
+ struct cbuf cbuf;
+ int error;
+
+ cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf));
+ cbuf.start = 0;
+ cbuf.end = TEST_BUF_SIZE - 1;
+
+#define STRING "abcdef"
+ error = cbuf_push(&cbuf, STRING, STRLEN(STRING) + 1, false);
+ check(error);
+#undef STRING
+}
+
+static void
+test_pop_buf(void)
{
- (void)argc;
- (void)argv;
+ char cbuf_buf[TEST_BUF_SIZE];
+ struct cbuf cbuf;
+ size_t size;
+ int error;
+
+ cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf));
+#define STRING "abcdef"
+ error = cbuf_push(&cbuf, STRING, STRLEN(STRING) + 1, false);
+ check(!error);
+ size = sizeof(cbuf_buf);
+ error = cbuf_pop(&cbuf, cbuf_buf, &size);
+ check(!error && (size == (STRLEN(STRING) + 1)));
+#undef STRING
+}
+
+static void
+test_pop_buf_overflow(void)
+{
+ char cbuf_buf[TEST_BUF_SIZE];
+ struct cbuf cbuf;
+ size_t size;
+ int error;
+
+ cbuf_init(&cbuf, cbuf_buf, sizeof(cbuf_buf));
+
+#define STRING "abcdef"
+ size = sizeof(cbuf_buf);
+ error = cbuf_pop(&cbuf, cbuf_buf, &size);
+ check(error);
+#undef STRING
+}
+
+int
+main(void)
+{
test_read_0();
test_read_regular();
test_read_overflow();
@@ -274,6 +341,10 @@ main(int argc, char *argv[])
test_append_overwrite();
test_write_regular();
test_write_overflow();
+ test_push_buf();
+ test_push_buf_overflow();
+ test_pop_buf();
+ test_pop_buf_overflow();
return 0;
}