summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/fstream/Makemodule.am2
-rw-r--r--lib/fstream/get_line.c118
-rw-r--r--lib/fstream/internal.h1
3 files changed, 120 insertions, 1 deletions
diff --git a/lib/fstream/Makemodule.am b/lib/fstream/Makemodule.am
index 0c24c6f..ad5f426 100644
--- a/lib/fstream/Makemodule.am
+++ b/lib/fstream/Makemodule.am
@@ -1,7 +1,7 @@
libfstream_a_SOURCES = include/fstream.h
libfstream_a_SOURCES += lib/fstream/internal.h
libfstream_a_SOURCES += lib/fstream/ostream.c lib/fstream/printf.c
-libfstream_a_SOURCES += lib/fstream/istream.c
+libfstream_a_SOURCES += lib/fstream/istream.c lib/fstream/get_line.c
libfstream_a_SOURCES += lib/fstream/compressor.c
libfstream_a_SOURCES += lib/fstream/compress/ostream_compressor.c
libfstream_a_SOURCES += lib/fstream/uncompress/istream_compressor.c
diff --git a/lib/fstream/get_line.c b/lib/fstream/get_line.c
new file mode 100644
index 0000000..f7e0b59
--- /dev/null
+++ b/lib/fstream/get_line.c
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * get_line.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "internal.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(istream_t *strm, char **out,
+ size_t *line_num, int flags)
+{
+ char *line = NULL, *new;
+ size_t i, line_len = 0;
+ bool have_line = false;
+
+ *out = NULL;
+
+ for (;;) {
+ if (istream_precache(strm))
+ return -1;
+
+ if (strm->buffer_used == 0) {
+ if (line_len == 0)
+ goto out_eof;
+
+ line_len = trim(line, flags);
+
+ if (line_len == 0 &&
+ (flags & ISTREAM_LINE_SKIP_EMPTY)) {
+ goto out_eof;
+ }
+ break;
+ }
+
+ for (i = 0; i < strm->buffer_used; ++i) {
+ if (strm->buffer[i] == '\n')
+ break;
+ }
+
+ if (i < strm->buffer_used) {
+ have_line = true;
+ strm->buffer_offset = i + 1;
+
+ if (i > 0 && strm->buffer[i - 1] == '\r')
+ --i;
+ } else {
+ strm->buffer_offset = i;
+ }
+
+ new = realloc(line, line_len + i + 1);
+ if (new == NULL)
+ goto fail_errno;
+
+ line = new;
+ memcpy(line + line_len, strm->buffer, i);
+ line_len += i;
+ line[line_len] = '\0';
+
+ if (have_line) {
+ line_len = trim(line, flags);
+
+ if (line_len == 0 &&
+ (flags & ISTREAM_LINE_SKIP_EMPTY)) {
+ free(line);
+ line = NULL;
+ have_line = false;
+ *line_num += 1;
+ continue;
+ }
+ break;
+ }
+ }
+
+ *out = line;
+ return 0;
+fail_errno:
+ fprintf(stderr, "%s: " PRI_SZ ": %s.\n", strm->get_filename(strm),
+ *line_num, strerror(errno));
+ free(line);
+ *out = NULL;
+ return -1;
+out_eof:
+ free(line);
+ *out = NULL;
+ return 1;
+}
diff --git a/lib/fstream/internal.h b/lib/fstream/internal.h
index 2dc81e4..4f02f8c 100644
--- a/lib/fstream/internal.h
+++ b/lib/fstream/internal.h
@@ -16,6 +16,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
+#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>