diff options
Diffstat (limited to 'lib/util/src')
-rw-r--r-- | lib/util/src/get_line.c | 130 |
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; +} |