aboutsummaryrefslogtreecommitdiff
path: root/lib/util
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-06-19 18:57:38 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-06-20 10:57:38 +0200
commitca9b6ba17257f88b8d575f18cab0b1e23660cfa5 (patch)
tree355d8dbedb496f0235b08aba1bb73e41ba4083ba /lib/util
parentcb5473418b1f3b26555e26840a87a6feed3f583b (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.am10
-rw-r--r--lib/util/src/get_line.c130
-rw-r--r--lib/util/test/get_line.c178
-rw-r--r--lib/util/test/str_table.c2
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"