Mercurial > molko
changeset 120:b3429b26d60d
core: add rbuf utility, closes #2488 @2h
author | David Demelier <markand@malikania.fr> |
---|---|
date | Mon, 05 Oct 2020 13:05:09 +0200 |
parents | 43e04bf2c350 |
children | 789b23e01f52 |
files | src/core/CMakeLists.txt src/core/rbuf.c src/core/rbuf.h tests/CMakeLists.txt tests/test-rbuf.c |
diffstat | 5 files changed, 294 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/core/CMakeLists.txt Mon Oct 05 09:17:11 2020 +0200 +++ b/src/core/CMakeLists.txt Mon Oct 05 13:05:09 2020 +0200 @@ -84,6 +84,8 @@ ${libcore_SOURCE_DIR}/panic.c ${libcore_SOURCE_DIR}/panic.h ${libcore_SOURCE_DIR}/plat.h + ${libcore_SOURCE_DIR}/rbuf.c + ${libcore_SOURCE_DIR}/rbuf.h ${libcore_SOURCE_DIR}/save.c ${libcore_SOURCE_DIR}/save.h ${libcore_SOURCE_DIR}/script.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/core/rbuf.c Mon Oct 05 13:05:09 2020 +0200 @@ -0,0 +1,57 @@ +/* + * rbuf.c -- basic utility for reading input buffers + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "rbuf.h" + +void +rbuf_open(struct rbuf *rb, const void *data, size_t datasz) +{ + assert(rb); + assert(data); + + rb->s = data; + rb->e = rb->s + datasz; +} + +bool +rbuf_readline(struct rbuf *rb, char *output, size_t outputsz) +{ + assert(rb); + assert(output); + assert(outputsz > 0); + + if (rb->s == rb->e) + return false; + + for (--outputsz; rb->s != rb->e && *rb->s != '\n' && outputsz; outputsz--) + *output++ = *rb->s++; + + /* Not enough space? */ + if (!outputsz && rb->s != rb->e && *rb->s != '\n') + return false; + + /* Remove this '\n' if still present. */ + if (rb->s != rb->e && *rb->s == '\n') + rb->s++; + + *output = '\0'; + + return true; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/core/rbuf.h Mon Oct 05 13:05:09 2020 +0200 @@ -0,0 +1,81 @@ +/* + * rbuf.h -- basic utility for reading input buffers + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_RBUF_H +#define MOLKO_RBUF_H + +/** + * \file rbuf.h + * \brief Basic utility for reading input buffers. + */ + +#include <stdbool.h> +#include <stddef.h> + +/** + * \brief Input object to store progression. + */ +struct rbuf { + const char *s; /*!< (RO) Pointer to current character. */ + const char *e; /*!< (RO) Pointer to end of array. */ +}; + +/** + * Open this input buffer. + * + * \pre rb != NULL + * \pre data != NULL + * \param rb the input object + * \param data the data to read + * \param datasz the size of buffer + */ +void +rbuf_open(struct rbuf *rb, const void *data, size_t datasz); + +/** + * Read the next line from the input. + * + * This function writes at most outputsz - 1 and is always NULL terminated + * unless the function returns false which indicates either end of buffer or + * too small output size. + * + * Example of use (`some_data` is assumed to be a buffer). + * + * \code + * struct rbuf rb; + * char line[1024]; + * + * rbuf_open(&rb, some_data, sizeof (some_data)); + * + * while (rbuf_readline(&rb, line, sizeof (line))) { + * printf("line contents: >[%s]<\n", line); + * } + * \endcode + * + * \pre rb != NULL + * \pre output != NULL + * \pre outputsz > 0 + * \param rb the input object + * \param output the output buffer + * \param outputsz the output buffer size + * \return true if a line was read correctly + */ +bool +rbuf_readline(struct rbuf *rb, char *output, size_t outputsz); + +#endif /* !MOLKO_RBUF_H */
--- a/tests/CMakeLists.txt Mon Oct 05 09:17:11 2020 +0200 +++ b/tests/CMakeLists.txt Mon Oct 05 13:05:09 2020 +0200 @@ -25,5 +25,6 @@ # Maps will be revamped. # molko_define_test(TARGET map SOURCES test-map.c ASSETS ${tests_SOURCE_DIR}/) # +molko_define_test(TARGET rbuf SOURCES test-rbuf.c) molko_define_test(TARGET save SOURCES test-save.c) molko_define_test(TARGET script SOURCES test-script.c)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-rbuf.c Mon Oct 05 13:05:09 2020 +0200 @@ -0,0 +1,153 @@ +/* + * test-rbuf.c -- test error routines + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define GREATEST_USE_ABBREVS 0 +#include <greatest.h> + +#include <rbuf.h> + +/* Don't use "" to avoid '\0' */ +const char data1[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f', '\n' }; +const char data2[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f' }; +const char data3[] = { 'a', 'b', 'c', '\n', '\n', 'd', 'e', 'f', '\n' }; +const char data4[] = { 'a', 'b', 'c', '\n', 'd', 'e', 'f', 'g', 'h', '\n' }; + +GREATEST_TEST +simple(void) +{ + struct rbuf rb; + char line[128]; + + rbuf_open(&rb, data1, sizeof (data1)); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("abc", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("def", line); + + GREATEST_PASS(); +} + +GREATEST_TEST +simple_noeol(void) +{ + struct rbuf rb; + char line[128]; + + rbuf_open(&rb, data2, sizeof (data2)); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("abc", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("def", line); + + GREATEST_PASS(); +} + +GREATEST_TEST +simple_emptylines(void) +{ + struct rbuf rb; + char line[128]; + + rbuf_open(&rb, data3, sizeof (data3)); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("abc", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("def", line); + + GREATEST_PASS(); +} + +GREATEST_SUITE(simple_suite) +{ + GREATEST_RUN_TEST(simple); + GREATEST_RUN_TEST(simple_noeol); + GREATEST_RUN_TEST(simple_emptylines); +} + +GREATEST_TEST +fail_toosmall(void) +{ + struct rbuf rb; + char line[4]; + + rbuf_open(&rb, data4, sizeof (data4)); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("abc", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(!rbuf_readline(&rb, line, sizeof (line))); + + GREATEST_PASS(); +} + +GREATEST_TEST +fail_end(void) +{ + struct rbuf rb; + char line[128]; + + rbuf_open(&rb, data1, sizeof (data1)); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("abc", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(rbuf_readline(&rb, line, sizeof (line))); + GREATEST_ASSERT_STR_EQ("def", line); + + memset(line, '?', sizeof (line)); + GREATEST_ASSERT(!rbuf_readline(&rb, line, sizeof (line))); + + GREATEST_PASS(); +} + +GREATEST_SUITE(fail_suite) +{ + GREATEST_RUN_TEST(fail_toosmall); + GREATEST_RUN_TEST(fail_end); +} + +GREATEST_MAIN_DEFS(); + +int +main(int argc, char **argv) +{ + GREATEST_MAIN_BEGIN(); + GREATEST_RUN_SUITE(simple_suite); + GREATEST_RUN_SUITE(fail_suite); + GREATEST_MAIN_END(); +}