aboutsummaryrefslogtreecommitdiff
path: root/lib/util/src/get_line.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/util/src/get_line.c')
-rw-r--r--lib/util/src/get_line.c130
1 files changed, 130 insertions, 0 deletions
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;
+}