From 230da6a3f29bf1c635db6151ee16b1d28bc8563a Mon Sep 17 00:00:00 2001 From: ado Date: Thu, 22 Feb 2024 23:59:58 +0100 Subject: [PATCH] Update getline implementation for non-POSIX systems --- include/ss/common.hpp | 68 +++++++++++++++++++++++-------------------- ssp.hpp | 67 ++++++++++++++++++++++-------------------- 2 files changed, 73 insertions(+), 62 deletions(-) diff --git a/include/ss/common.hpp b/include/ss/common.hpp index 7531e29..dc08dc2 100644 --- a/include/ss/common.hpp +++ b/include/ss/common.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include #include +#include #include namespace ss { @@ -12,6 +14,7 @@ using string_range = std::pair; using split_data = std::vector; constexpr inline auto default_delimiter = ","; +constexpr inline auto get_line_initial_buffer_size = 128; template inline void assert_string_error_defined() { @@ -30,55 +33,58 @@ inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) { return getline(lineptr, n, stream); } #else -using ssize_t = int64_t; -inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) { - size_t pos; - int c; - if (lineptr == nullptr || stream == nullptr || n == nullptr) { +using ssize_t = int64_t; + +ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { + if (lineptr == nullptr || n == nullptr || fp == nullptr) { errno = EINVAL; return -1; } - c = getc(stream); - if (c == EOF) { - return -1; - } + char buff[get_line_initial_buffer_size]; - if (*lineptr == nullptr) { - *lineptr = static_cast(malloc(128)); - if (*lineptr == nullptr) { + if (*lineptr == nullptr || *n < sizeof(buff)) { + *n = sizeof(buff); + auto new_lineptr = static_cast(realloc(*lineptr, *n)); + if (new_lineptr == nullptr) { + errno = ENOMEM; return -1; } - *n = 128; + + *lineptr = new_lineptr; } - pos = 0; - while (c != EOF) { - if (pos + 1 >= *n) { - size_t new_size = *n + (*n >> 2); - if (new_size < 128) { - new_size = 128; - } - char* new_ptr = static_cast( - realloc(static_cast(*lineptr), new_size)); - if (new_ptr == nullptr) { + (*lineptr)[0] = '\0'; + + while (fgets(buff, sizeof(buff), fp) != nullptr) { + size_t line_used = strlen(*lineptr); + size_t buff_used = strlen(buff); + + if (*n < buff_used + line_used) { + *n *= 2; + + auto new_lineptr = static_cast(realloc(*lineptr, *n)); + if (new_lineptr == nullptr) { + errno = ENOMEM; return -1; } - *n = new_size; - *lineptr = new_ptr; + + *lineptr = new_lineptr; } - (*lineptr)[pos++] = c; - if (c == '\n') { - break; + memcpy(*lineptr + line_used, buff, buff_used); + line_used += buff_used; + (*lineptr)[line_used] = '\0'; + + if ((*lineptr)[line_used - 1] == '\n') { + return line_used; } - c = getc(stream); } - (*lineptr)[pos] = '\0'; - return pos; + return -1; } + #endif } /* ss */ diff --git a/ssp.hpp b/ssp.hpp index d66e595..ee06e2b 100644 --- a/ssp.hpp +++ b/ssp.hpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -625,6 +626,7 @@ using string_range = std::pair; using split_data = std::vector; constexpr inline auto default_delimiter = ","; +constexpr inline auto get_line_initial_buffer_size = 128; template inline void assert_string_error_defined() { @@ -643,55 +645,58 @@ inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) { return getline(lineptr, n, stream); } #else -using ssize_t = int64_t; -inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) { - size_t pos; - int c; - if (lineptr == nullptr || stream == nullptr || n == nullptr) { +using ssize_t = int64_t; + +ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { + if (lineptr == nullptr || n == nullptr || fp == nullptr) { errno = EINVAL; return -1; } - c = getc(stream); - if (c == EOF) { - return -1; - } + char buff[get_line_initial_buffer_size]; - if (*lineptr == nullptr) { - *lineptr = static_cast(malloc(128)); - if (*lineptr == nullptr) { + if (*lineptr == nullptr || *n < sizeof(buff)) { + *n = sizeof(buff); + auto new_lineptr = static_cast(realloc(*lineptr, *n)); + if (new_lineptr == nullptr) { + errno = ENOMEM; return -1; } - *n = 128; + + *lineptr = new_lineptr; } - pos = 0; - while (c != EOF) { - if (pos + 1 >= *n) { - size_t new_size = *n + (*n >> 2); - if (new_size < 128) { - new_size = 128; - } - char* new_ptr = static_cast( - realloc(static_cast(*lineptr), new_size)); - if (new_ptr == nullptr) { + (*lineptr)[0] = '\0'; + + while (fgets(buff, sizeof(buff), fp) != nullptr) { + size_t line_used = strlen(*lineptr); + size_t buff_used = strlen(buff); + + if (*n < buff_used + line_used) { + *n *= 2; + + auto new_lineptr = static_cast(realloc(*lineptr, *n)); + if (new_lineptr == nullptr) { + errno = ENOMEM; return -1; } - *n = new_size; - *lineptr = new_ptr; + + *lineptr = new_lineptr; } - (*lineptr)[pos++] = c; - if (c == '\n') { - break; + memcpy(*lineptr + line_used, buff, buff_used); + line_used += buff_used; + (*lineptr)[line_used] = '\0'; + + if ((*lineptr)[line_used - 1] == '\n') { + return line_used; } - c = getc(stream); } - (*lineptr)[pos] = '\0'; - return pos; + return -1; } + #endif } /* ss */