diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-06-19 18:57:38 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-06-20 10:57:38 +0200 |
commit | ca9b6ba17257f88b8d575f18cab0b1e23660cfa5 (patch) | |
tree | 355d8dbedb496f0235b08aba1bb73e41ba4083ba /lib/util | |
parent | cb5473418b1f3b26555e26840a87a6feed3f583b (diff) |
Move istream_get_line function to libutil
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/util')
-rw-r--r-- | lib/util/Makemodule.am | 10 | ||||
-rw-r--r-- | lib/util/src/get_line.c | 130 | ||||
-rw-r--r-- | lib/util/test/get_line.c | 178 | ||||
-rw-r--r-- | lib/util/test/str_table.c | 2 |
4 files changed, 316 insertions, 4 deletions
diff --git a/lib/util/Makemodule.am b/lib/util/Makemodule.am index a797930..1ca4802 100644 --- a/lib/util/Makemodule.am +++ b/lib/util/Makemodule.am @@ -1,6 +1,6 @@ libutil_a_SOURCES = include/util/util.h include/util/str_table.h \ include/util/hash_table.h include/util/test.h include/util/rbtree.h \ - include/util/array.h include/util/threadpool.h \ + include/util/array.h include/util/threadpool.h include/util/parse.h \ include/util/w32threadwrap.h include/util/mempool.h \ lib/util/src/str_table.c lib/util/src/alloc.c lib/util/src/rbtree.c \ lib/util/src/array.c lib/util/src/xxhash.c lib/util/src/hash_table.c \ @@ -8,7 +8,8 @@ libutil_a_SOURCES = include/util/util.h include/util/str_table.h \ lib/util/src/is_memory_zero.c lib/util/src/mkdir_p.c \ lib/util/src/canonicalize_name.c lib/util/src/filename_sane.c \ lib/util/src/source_date_epoch.c lib/util/src/file_cmp.c \ - lib/util/src/hex_decode.c lib/util/src/base64_decode.c + lib/util/src/hex_decode.c lib/util/src/base64_decode.c \ + lib/util/src/get_line.c libutil_a_CFLAGS = $(AM_CFLAGS) libutil_a_CPPFLAGS = $(AM_CPPFLAGS) @@ -76,10 +77,13 @@ test_hex_decode_LDADD = libutil.a libcompat.a test_base64_decode_SOURCES = lib/util/test/base64_decode.c test_base64_decode_LDADD = libutil.a libcompat.a +test_get_line_SOURCES = lib/util/test/get_line.c +test_get_line_LDADD = libutil.a libio.a libcompat.a + LIBUTIL_TESTS = \ test_str_table test_rbtree test_xxhash test_threadpool test_ismemzero \ test_canonicalize_name test_filename_sane test_filename_sane_w32 \ - test_sdate_epoch test_hex_decode test_base64_decode + test_sdate_epoch test_hex_decode test_base64_decode test_get_line check_PROGRAMS += $(LIBUTIL_TESTS) TESTS += $(LIBUTIL_TESTS) diff --git a/lib/util/src/get_line.c b/lib/util/src/get_line.c new file mode 100644 index 0000000..5a17b62 --- /dev/null +++ b/lib/util/src/get_line.c @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * get_line.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "util/parse.h" +#include "sqfs/io.h" +#include "sqfs/error.h" +#include "compat.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +static void ltrim(char *buffer) +{ + size_t i = 0; + + while (isspace(buffer[i])) + ++i; + + if (i > 0) + memmove(buffer, buffer + i, strlen(buffer + i) + 1); +} + +static void rtrim(char *buffer) +{ + size_t i = strlen(buffer); + + while (i > 0 && isspace(buffer[i - 1])) + --i; + + buffer[i] = '\0'; +} + +static size_t trim(char *buffer, int flags) +{ + if (flags & ISTREAM_LINE_LTRIM) + ltrim(buffer); + + if (flags & ISTREAM_LINE_RTRIM) + rtrim(buffer); + + return strlen(buffer); +} + +int istream_get_line(sqfs_istream_t *strm, char **out, + size_t *line_num, int flags) +{ + char *line = NULL, *new; + size_t line_len = 0; + int err; + + for (;;) { + bool have_line = false; + size_t i, count, avail; + const sqfs_u8 *ptr; + + err = strm->get_buffered_data(strm, &ptr, &avail, 0); + if (err < 0) + goto fail; + if (err > 0) { + if (line_len == 0) + goto out_eof; + + line_len = trim(line, flags); + if (line_len > 0 ||!(flags & ISTREAM_LINE_SKIP_EMPTY)) + break; + + goto out_eof; + } + + for (i = 0; i < avail; ++i) { + if (ptr[i] == '\n') + break; + } + + if (i < avail) { + count = i++; + have_line = true; + } else { + count = i; + } + + new = realloc(line, line_len + count + 1); + if (new == NULL) { + err = SQFS_ERROR_ALLOC; + goto fail; + } + + line = new; + memcpy(line + line_len, ptr, count); + line_len += count; + line[line_len] = '\0'; + + strm->advance_buffer(strm, i); + + if (have_line) { + if (line_len > 0 && line[line_len - 1] == '\r') + line[--line_len] = '\0'; + + line_len = trim(line, flags); + if (line_len > 0 || !(flags & ISTREAM_LINE_SKIP_EMPTY)) + break; + + free(line); + line = NULL; + *line_num += 1; + } + } + + new = realloc(line, line_len + 1); + if (new != NULL) + line = new; + + *out = line; + return 0; +fail: { + os_error_t temp = get_os_error_state(); + free(line); + *out = NULL; + set_os_error_state(temp); + return err; +} +out_eof: + free(line); + *out = NULL; + return 1; +} diff --git a/lib/util/test/get_line.c b/lib/util/test/get_line.c new file mode 100644 index 0000000..6189d31 --- /dev/null +++ b/lib/util/test/get_line.c @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * get_line.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "util/parse.h" +#include "io/mem.h" +#include "util/test.h" + +typedef struct { + size_t line_num; + const char *str; +} line_t; + +static void run_test_case(const char *raw, const line_t *lines, size_t count, + int flags) +{ + size_t i, line_num, old_line_num; + sqfs_istream_t *fp; + char *line; + int ret; + + fp = istream_memory_create("lines.txt", 2, raw, strlen(raw)); + TEST_NOT_NULL(fp); + + line_num = 1; + line = NULL; + + for (i = 0; i < count; ++i) { + old_line_num = line_num; + ret = istream_get_line(fp, &line, &line_num, flags); + + TEST_ASSERT(line_num >= old_line_num); + TEST_EQUAL_I(ret, 0); + TEST_NOT_NULL(line); + + TEST_EQUAL_UI(line_num, lines[i].line_num); + TEST_STR_EQUAL(line, lines[i].str); + + free(line); + line = NULL; + line_num += 1; + } + + ret = istream_get_line(fp, &line, &line_num, flags); + TEST_ASSERT(ret > 0); + + sqfs_drop(fp); +} + +static const char *file = +"\r\n" +"The quick\r\n" +" \r\n" +" brown fox \r\n" +"\r\n" +"jumps over\r\n" +"the\r\n" +"lazy\r\n" +"\r\n" +"dog\r\n" +"\r\n"; + +static const line_t lines_raw[] = { + { 1, "" }, + { 2, "The quick" }, + { 3, " " }, + { 4, " brown fox " }, + { 5, "" }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 9, "" }, + { 10, "dog" }, + { 11, "" }, +}; + +static const line_t lines_ltrim[] = { + { 1, "" }, + { 2, "The quick" }, + { 3, "" }, + { 4, "brown fox " }, + { 5, "" }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 9, "" }, + { 10, "dog" }, + { 11, "" }, +}; + +static const line_t lines_rtrim[] = { + { 1, "" }, + { 2, "The quick" }, + { 3, "" }, + { 4, " brown fox" }, + { 5, "" }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 9, "" }, + { 10, "dog" }, + { 11, "" }, +}; + +static const line_t lines_trim[] = { + { 1, "" }, + { 2, "The quick" }, + { 3, "" }, + { 4, "brown fox" }, + { 5, "" }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 9, "" }, + { 10, "dog" }, + { 11, "" }, +}; + +static const line_t lines_no_empty[] = { + { 2, "The quick" }, + { 3, " " }, + { 4, " brown fox " }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 10, "dog" }, +}; + +static const line_t lines_no_empty_ltrim[] = { + { 2, "The quick" }, + { 4, "brown fox " }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 10, "dog" }, +}; + +static const line_t lines_no_empty_rtrim[] = { + { 2, "The quick" }, + { 4, " brown fox" }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 10, "dog" }, +}; + +static const line_t lines_no_empty_trim[] = { + { 2, "The quick" }, + { 4, "brown fox" }, + { 6, "jumps over" }, + { 7, "the" }, + { 8, "lazy" }, + { 10, "dog" }, +}; + +int main(int argc, char **argv) +{ + (void)argc; (void)argv; + + run_test_case(file, lines_raw, 11, 0); + run_test_case(file, lines_ltrim, 11, ISTREAM_LINE_LTRIM); + run_test_case(file, lines_rtrim, 11, ISTREAM_LINE_RTRIM); + run_test_case(file, lines_trim, 11, + ISTREAM_LINE_LTRIM | ISTREAM_LINE_RTRIM); + + run_test_case(file, lines_no_empty, 7, ISTREAM_LINE_SKIP_EMPTY); + run_test_case(file, lines_no_empty_ltrim, 6, + ISTREAM_LINE_SKIP_EMPTY | ISTREAM_LINE_LTRIM); + run_test_case(file, lines_no_empty_rtrim, 6, + ISTREAM_LINE_SKIP_EMPTY | ISTREAM_LINE_RTRIM); + run_test_case(file, lines_no_empty_trim, 6, + ISTREAM_LINE_SKIP_EMPTY | ISTREAM_LINE_LTRIM | + ISTREAM_LINE_RTRIM); + + return EXIT_SUCCESS; +} diff --git a/lib/util/test/str_table.c b/lib/util/test/str_table.c index b146773..153d09e 100644 --- a/lib/util/test/str_table.c +++ b/lib/util/test/str_table.c @@ -7,8 +7,8 @@ #include "config.h" #include "util/str_table.h" +#include "util/parse.h" #include "compat.h" -#include "io/istream.h" #include "util/test.h" #include "sqfs/io.h" |