From 8881649aca9d5d7efca9730dc8ed1098cd3c69d5 Mon Sep 17 00:00:00 2001 From: ado Date: Fri, 23 Feb 2024 23:25:03 +0100 Subject: [PATCH] Update get_line_buffer, update new version of get_line_file to work with data that has no new line at eof --- include/ss/common.hpp | 9 ++++--- include/ss/parser.hpp | 54 +++++++++++++++++++++-------------------- test/test_parser1_1.cpp | 13 ++++++++++ 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/include/ss/common.hpp b/include/ss/common.hpp index 95953c6..4493cc3 100644 --- a/include/ss/common.hpp +++ b/include/ss/common.hpp @@ -58,14 +58,15 @@ ssize_t get_line_file(char** lineptr, size_t* n, FILE* fp) { (*lineptr)[0] = '\0'; + size_t line_used = 0; while (fgets(buff, sizeof(buff), fp) != nullptr) { - size_t line_used = strlen(*lineptr); + line_used = strlen(*lineptr); size_t buff_used = strlen(buff); - if (*n < buff_used + line_used) { + if (*n <= buff_used + line_used) { size_t new_n = *n * 2; - auto new_lineptr = static_cast(realloc(*lineptr, *n)); + auto new_lineptr = static_cast(realloc(*lineptr, new_n)); if (new_lineptr == nullptr) { errno = ENOMEM; return -1; @@ -84,7 +85,7 @@ ssize_t get_line_file(char** lineptr, size_t* n, FILE* fp) { } } - return -1; + return (line_used != 0) ? line_used : -1; } #endif diff --git a/include/ss/parser.hpp b/include/ss/parser.hpp index e11969e..c19b834 100644 --- a/include/ss/parser.hpp +++ b/include/ss/parser.hpp @@ -744,50 +744,52 @@ private: reader& operator=(const reader& other) = delete; ssize_t get_line_buffer(char** lineptr, size_t* n, - const char* const buffer, size_t csv_data_size, - size_t& curr_char) { - size_t pos; - int c; + const char* const csv_data_buffer, + size_t csv_data_size, size_t& curr_char) { + if (lineptr == nullptr || n == nullptr || + csv_data_buffer == nullptr) { + errno = EINVAL; + return -1; + } if (curr_char >= csv_data_size) { return -1; } - c = buffer[curr_char++]; - if (*lineptr == nullptr) { - *lineptr = - static_cast(malloc(get_line_initial_buffer_size)); - if (*lineptr == nullptr) { + if (*lineptr == nullptr || *n < get_line_initial_buffer_size) { + auto new_lineptr = static_cast( + realloc(*lineptr, get_line_initial_buffer_size)); + if (new_lineptr == nullptr) { return -1; } - *n = 128; + *lineptr = new_lineptr; + *n = get_line_initial_buffer_size; } - pos = 0; + size_t line_used = 0; while (curr_char <= csv_data_size) { - if (pos + 1 >= *n) { - size_t new_size = *n + (*n >> 2); - if (new_size < get_line_initial_buffer_size) { - new_size = get_line_initial_buffer_size; - } - char* new_ptr = static_cast( - realloc(static_cast(*lineptr), new_size)); - if (new_ptr == nullptr) { + if (line_used + 1 >= *n) { + size_t new_n = *n * 2; + + char* new_lineptr = + static_cast(realloc(*lineptr, new_n)); + if (new_lineptr == nullptr) { + errno = ENOMEM; return -1; } - *n = new_size; - *lineptr = new_ptr; + *n = new_n; + *lineptr = new_lineptr; } - (*lineptr)[pos++] = c; + auto c = csv_data_buffer[curr_char++]; + (*lineptr)[line_used++] = c; if (c == '\n') { - break; + (*lineptr)[line_used] = '\0'; + return line_used; } - c = buffer[curr_char++]; } - (*lineptr)[pos] = '\0'; - return pos; + return (line_used != 0) ? line_used : -1; } // read next line each time in order to set eof_ diff --git a/test/test_parser1_1.cpp b/test/test_parser1_1.cpp index 4c8d476..47adbd2 100644 --- a/test/test_parser1_1.cpp +++ b/test/test_parser1_1.cpp @@ -571,9 +571,22 @@ template void test_no_new_line_at_eof() { test_no_new_line_at_eof_impl({}); test_no_new_line_at_eof_impl({{1, 2, "X"}}); + test_no_new_line_at_eof_impl({{1, 2, "X"}, {}}); test_no_new_line_at_eof_impl({{1, 2, "X"}, {3, 4, "YY"}}); + test_no_new_line_at_eof_impl({{1, 2, "X"}, {3, 4, "YY"}, {}}); test_no_new_line_at_eof_impl( {{1, 2, "X"}, {3, 4, "YY"}, {5, 6, "ZZZ"}, {7, 8, "UUU"}}); + + for (size_t i = 0; i < 2 * ss::get_line_initial_buffer_size; ++i) { + test_no_new_line_at_eof_impl( + {{1, 2, std::string(i, 'X')}}); + + for (size_t j = 0; j < 2 * ss::get_line_initial_buffer_size; ++j) { + + test_no_new_line_at_eof_impl( + {{1, 2, std::string(i, 'X')}, {3, 4, std::string(j, 'Y')}}); + } + } } TEST_CASE("test no new line at end of data") {