From 230da6a3f29bf1c635db6151ee16b1d28bc8563a Mon Sep 17 00:00:00 2001 From: ado Date: Thu, 22 Feb 2024 23:59:58 +0100 Subject: [PATCH 1/4] 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 */ From ea21b9ba049970b069677b8114ef336cabe3a661 Mon Sep 17 00:00:00 2001 From: ado Date: Fri, 23 Feb 2024 00:59:58 +0100 Subject: [PATCH 2/4] Fix get_line possible leak --- include/ss/common.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/ss/common.hpp b/include/ss/common.hpp index dc08dc2..45c4234 100644 --- a/include/ss/common.hpp +++ b/include/ss/common.hpp @@ -28,7 +28,7 @@ inline void assert_throw_on_error_not_defined() { "'throw_on_error' is enabled"); } -#if __unix__ +#if __unix__XX inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) { return getline(lineptr, n, stream); } @@ -45,14 +45,15 @@ ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { char buff[get_line_initial_buffer_size]; if (*lineptr == nullptr || *n < sizeof(buff)) { - *n = sizeof(buff); - auto new_lineptr = static_cast(realloc(*lineptr, *n)); + size_t new_n = sizeof(buff); + auto new_lineptr = static_cast(realloc(*lineptr, new_n)); if (new_lineptr == nullptr) { errno = ENOMEM; return -1; } *lineptr = new_lineptr; + *n = new_n; } (*lineptr)[0] = '\0'; @@ -62,7 +63,7 @@ ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { size_t buff_used = strlen(buff); if (*n < buff_used + line_used) { - *n *= 2; + size_t new_n = *n * 2; auto new_lineptr = static_cast(realloc(*lineptr, *n)); if (new_lineptr == nullptr) { @@ -71,6 +72,7 @@ ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { } *lineptr = new_lineptr; + *n = new_n; } memcpy(*lineptr + line_used, buff, buff_used); From 09e628020d394c1fcbfea3a9e1bfceff556d7839 Mon Sep 17 00:00:00 2001 From: ado Date: Fri, 23 Feb 2024 01:01:31 +0100 Subject: [PATCH 3/4] Fix typo in common.hpp --- include/ss/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ss/common.hpp b/include/ss/common.hpp index 45c4234..305503c 100644 --- a/include/ss/common.hpp +++ b/include/ss/common.hpp @@ -28,7 +28,7 @@ inline void assert_throw_on_error_not_defined() { "'throw_on_error' is enabled"); } -#if __unix__XX +#if __unix__ inline ssize_t get_line(char** lineptr, size_t* n, FILE* stream) { return getline(lineptr, n, stream); } From c0ee100f99e22fe0a587235b06b1f0d9a52b376c Mon Sep 17 00:00:00 2001 From: ado Date: Fri, 23 Feb 2024 01:04:40 +0100 Subject: [PATCH 4/4] Update ssp.hpp --- ssp.hpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ssp.hpp b/ssp.hpp index ee06e2b..9bc953b 100644 --- a/ssp.hpp +++ b/ssp.hpp @@ -657,14 +657,15 @@ ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { char buff[get_line_initial_buffer_size]; if (*lineptr == nullptr || *n < sizeof(buff)) { - *n = sizeof(buff); - auto new_lineptr = static_cast(realloc(*lineptr, *n)); + size_t new_n = sizeof(buff); + auto new_lineptr = static_cast(realloc(*lineptr, new_n)); if (new_lineptr == nullptr) { errno = ENOMEM; return -1; } *lineptr = new_lineptr; + *n = new_n; } (*lineptr)[0] = '\0'; @@ -674,7 +675,7 @@ ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { size_t buff_used = strlen(buff); if (*n < buff_used + line_used) { - *n *= 2; + size_t new_n = *n * 2; auto new_lineptr = static_cast(realloc(*lineptr, *n)); if (new_lineptr == nullptr) { @@ -683,6 +684,7 @@ ssize_t get_line(char** lineptr, size_t* n, FILE* fp) { } *lineptr = new_lineptr; + *n = new_n; } memcpy(*lineptr + line_used, buff, buff_used);