From e38c13a76435bfccf274636c144634b33211c29f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 17 Jan 2025 22:59:44 -0500 Subject: [PATCH] add strcompress function and use it for error output --- doc/src/Developer_utils.rst | 3 +++ src/utils.cpp | 32 +++++++++++++++++++++++++++--- src/utils.h | 15 ++++++++++---- unittest/utils/test_utils.cpp | 37 ++++++++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index 2f9dce86d4..86a536f0cd 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -133,6 +133,9 @@ and parsing files or arguments. .. doxygenfunction:: trim_comment :project: progguide +.. doxygenfunction:: strcompress + :project: progguide + .. doxygenfunction:: strip_style_suffix :project: progguide diff --git a/src/utils.cpp b/src/utils.cpp index 4f1a0cb3fa..71a662a7e9 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -119,8 +119,8 @@ bool utils::strsame(const std::string &text1, const std::string &text2) while (*ptr1 && *ptr2) { // ignore whitespace - while (*ptr1 && isblank(*ptr1)) ++ptr1; - while (*ptr2 && isblank(*ptr2)) ++ptr2; + while (*ptr1 && isspace(*ptr1)) ++ptr1; + while (*ptr2 && isspace(*ptr2)) ++ptr2; // strings differ if (*ptr1 != *ptr2) return false; @@ -134,6 +134,32 @@ bool utils::strsame(const std::string &text1, const std::string &text2) return true; } +std::string utils::strcompress(const std::string &text) +{ + const char *ptr = text.c_str(); + std::string output; + + // remove leading whitespace + while (*ptr && isspace(*ptr)) ++ptr; + + while (*ptr) { + // copy non-blank characters + while (*ptr && !isspace(*ptr)) output += *ptr++; + + if (!*ptr) break; + + // add one blank only + if (isspace(*ptr)) output += ' '; + + // skip additional blanks + while (*ptr && isspace(*ptr)) ++ptr; + } + + // remove trailing blank + if (output.back() == ' ') output.erase(output.size() - 1, 1); + return output; +} + /** This function is a companion function to utils::strmatch(). Arguments * and logic is the same, but instead of a boolean, it returns the * sub-string that matches the regex pattern. There can be only one match. @@ -158,7 +184,7 @@ void utils::missing_cmd_args(const std::string &file, int line, const std::strin std::string utils::point_to_error(Input *input, int failed) { if (input) { - std::string lastline = input->line; + std::string lastline = utils::strcompress(input->line); std::string lastargs = input->command; std::string cmdline = "Last input line: "; diff --git a/src/utils.h b/src/utils.h index 598ff56eb3..21300c4943 100644 --- a/src/utils.h +++ b/src/utils.h @@ -35,20 +35,27 @@ namespace utils { /*! Match text against a simplified regex pattern * - * \param text the text to be matched against the pattern - * \param pattern the search pattern, which may contain regexp markers + * \param text the text to be matched against the pattern + * \param pattern the search pattern, which may contain regexp markers * \return true if the pattern matches, false if not */ bool strmatch(const std::string &text, const std::string &pattern); /*! Compare two string while ignoring whitespace * - * \param text1 the first text to be compared - * \param text2 the second text to be compared + * \param text1 the first text to be compared + * \param text2 the second text to be compared * \return true if the non-whitespace part of the two strings matches, false if not */ bool strsame(const std::string &text1, const std::string &text2); + /*! Compress whitespace in a string + * + * \param text the text to be compressed + * \return string with whitespace compressed to single blanks */ + + std::string strcompress(const std::string &text); + /*! Find sub-string that matches a simplified regex pattern * * \param text the text to be matched against the pattern diff --git a/unittest/utils/test_utils.cpp b/unittest/utils/test_utils.cpp index 2a46de43f7..cb6fb9c05b 100644 --- a/unittest/utils/test_utils.cpp +++ b/unittest/utils/test_utils.cpp @@ -50,16 +50,43 @@ TEST(Utils, strsame) { std::string text1("some_text"); std::string text2("some_text"); - ASSERT_TRUE(utils::strsame(text1,text2)); + ASSERT_TRUE(utils::strsame(text1, text2)); text1 = " some _\ttext\n "; - ASSERT_TRUE(utils::strsame(text1,text2)); + ASSERT_TRUE(utils::strsame(text1, text2)); text2 = " some _ text\n "; - ASSERT_TRUE(utils::strsame(text1,text2)); + ASSERT_TRUE(utils::strsame(text1, text2)); text2 = "some_other_text"; - ASSERT_FALSE(utils::strsame(text1,text2)); + ASSERT_FALSE(utils::strsame(text1, text2)); text2 = " some other_text"; - ASSERT_FALSE(utils::strsame(text1,text2)); + ASSERT_FALSE(utils::strsame(text1, text2)); +} + +TEST(Utils, strcompress) +{ + auto compressed = utils::strcompress("\t some text "); + ASSERT_THAT(compressed, StrEq("some text")); + + compressed = utils::strcompress("some \ntext"); + ASSERT_THAT(compressed, StrEq("some text")); + + compressed = utils::strcompress("sometext"); + ASSERT_THAT(compressed, StrEq("sometext")); + + compressed = utils::strcompress("some text \r\n"); + ASSERT_THAT(compressed, StrEq("some text")); + + compressed = utils::strcompress("some other text \r\n"); + ASSERT_THAT(compressed, StrEq("some other text")); + + compressed = utils::strcompress("\v some text \f"); + ASSERT_THAT(compressed, StrEq("some text")); + + compressed = utils::strcompress(" some\t text "); + ASSERT_THAT(compressed, StrEq("some text")); + + compressed = utils::strcompress(" \t\n "); + ASSERT_THAT(compressed, StrEq("")); } TEST(Utils, trim)