From 6b343cf4097dd69ec15391abb400a91857077b7e Mon Sep 17 00:00:00 2001 From: Jochen Topf Date: Sat, 19 Apr 2025 17:40:08 +0200 Subject: [PATCH 1/2] Fix two bugs in wildcard match Two or more consecutive * characters were not handled. A fix was on the web site this code comes from. Before calling wildMatch recursively with "str + 1", the code did not check whether *str was zero, in which case the "str + 1" is illegal. This also changes the names of the function parameters which were not consistent in .hpp and .cpp files. --- src/wildcmp.cpp | 27 ++++++++++++++++++--------- src/wildcmp.hpp | 2 +- tests/test-wildcard-match.cpp | 5 +++++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/wildcmp.cpp b/src/wildcmp.cpp index 40b1d35a7..bc7365194 100644 --- a/src/wildcmp.cpp +++ b/src/wildcmp.cpp @@ -15,28 +15,37 @@ * Case sensitive wild card match with a string. * * matches any string or no character. * ? matches any single character. - * anything else etc must match the character exactly. + * anything else must match the character exactly. * * Returns if a match was found. */ -bool wildMatch(char const *first, char const *second) +bool wildMatch(char const *expr, char const *str) noexcept { - // Code borrowed from + // Code based on // http://www.geeksforgeeks.org/wildcard-character-matching/ - if (*first == '\0' && *second == '\0') { + if (*expr == '\0' && *str == '\0') { return true; } - if (*first == '*' && *(first + 1) != '\0' && *second == '\0') { + if (*expr == '*') { + while (*(expr + 1) == '*') { + ++expr; + } + } + + if (*expr == '*' && *(expr + 1) != '\0' && *str == '\0') { return false; } - if (*first == '?' || *first == *second) { - return wildMatch(first + 1, second + 1); + if (*expr == '?' || *expr == *str) { + if (*str == '\0') { + return false; + } + return wildMatch(expr + 1, str + 1); } - if (*first == '*') { - return wildMatch(first + 1, second) || wildMatch(first, second + 1); + if (*expr == '*') { + return wildMatch(expr + 1, str) || wildMatch(expr, str + 1); } return false; diff --git a/src/wildcmp.hpp b/src/wildcmp.hpp index 2ad8a080d..e6a4c84e3 100644 --- a/src/wildcmp.hpp +++ b/src/wildcmp.hpp @@ -10,6 +10,6 @@ * For a full list of authors see the git log. */ -bool wildMatch(char const *wildCard, char const *string); +bool wildMatch(char const *expr, char const *str) noexcept; #endif // OSM2PGSQL_WILDCMP_HPP diff --git a/tests/test-wildcard-match.cpp b/tests/test-wildcard-match.cpp index 5eb10c7bd..0676d23c4 100644 --- a/tests/test-wildcard-match.cpp +++ b/tests/test-wildcard-match.cpp @@ -17,14 +17,17 @@ TEST_CASE("Wildcard matching", "[NoDB]") CHECK_FALSE(wildMatch("fhwieurwe", "fhwieurw")); CHECK_FALSE(wildMatch("fhwieurw", "fhwieurwe")); CHECK(wildMatch("*", "foo")); + CHECK(wildMatch("**", "foo")); CHECK_FALSE(wildMatch("r*", "foo")); CHECK(wildMatch("r*", "roo")); CHECK(wildMatch("*bar", "Hausbar")); CHECK_FALSE(wildMatch("*bar", "Haustar")); CHECK(wildMatch("*", "")); + CHECK(wildMatch("**", "")); CHECK(wildMatch("kin*la", "kinla")); CHECK(wildMatch("kin*la", "kinLLla")); CHECK(wildMatch("kin*la", "kinlalalala")); + CHECK(wildMatch("kin**la", "kinlalalala")); CHECK_FALSE(wildMatch("kin*la", "kinlaa")); CHECK_FALSE(wildMatch("kin*la", "ki??laa")); CHECK(wildMatch("1*2*3", "123")); @@ -35,4 +38,6 @@ TEST_CASE("Wildcard matching", "[NoDB]") CHECK_FALSE(wildMatch("bo??f", "boxf")); CHECK(wildMatch("?5?", "?5?")); CHECK(wildMatch("?5?", "x5x")); + CHECK_FALSE(wildMatch("?abc", "")); + CHECK_FALSE(wildMatch("?", "")); } From 1d693eba90cb1910e578459e586a9f3af13f2571 Mon Sep 17 00:00:00 2001 From: Jochen Topf Date: Sat, 19 Apr 2025 20:21:25 +0200 Subject: [PATCH 2/2] Rename wildMatch() to wild_match() To use our normal naming convention. --- src/tagtransform-c.cpp | 2 +- src/wildcmp.cpp | 6 ++-- src/wildcmp.hpp | 2 +- tests/test-wildcard-match.cpp | 54 +++++++++++++++++------------------ 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/tagtransform-c.cpp b/src/tagtransform-c.cpp index c471d8541..9c1e34153 100644 --- a/src/tagtransform-c.cpp +++ b/src/tagtransform-c.cpp @@ -112,7 +112,7 @@ bool c_tagtransform_t::check_key(std::vector const &infos, //go through the actual tags found on the item and keep the ones in the export list for (auto const &info : infos) { if (info.flags & FLAG_DELETE) { - if (wildMatch(info.name.c_str(), k)) { + if (wild_match(info.name.c_str(), k)) { return false; } } else if (std::strcmp(info.name.c_str(), k) == 0) { diff --git a/src/wildcmp.cpp b/src/wildcmp.cpp index bc7365194..9ae36d49b 100644 --- a/src/wildcmp.cpp +++ b/src/wildcmp.cpp @@ -19,7 +19,7 @@ * * Returns if a match was found. */ -bool wildMatch(char const *expr, char const *str) noexcept +bool wild_match(char const *expr, char const *str) noexcept { // Code based on // http://www.geeksforgeeks.org/wildcard-character-matching/ @@ -41,11 +41,11 @@ bool wildMatch(char const *expr, char const *str) noexcept if (*str == '\0') { return false; } - return wildMatch(expr + 1, str + 1); + return wild_match(expr + 1, str + 1); } if (*expr == '*') { - return wildMatch(expr + 1, str) || wildMatch(expr, str + 1); + return wild_match(expr + 1, str) || wild_match(expr, str + 1); } return false; diff --git a/src/wildcmp.hpp b/src/wildcmp.hpp index e6a4c84e3..b471fa5aa 100644 --- a/src/wildcmp.hpp +++ b/src/wildcmp.hpp @@ -10,6 +10,6 @@ * For a full list of authors see the git log. */ -bool wildMatch(char const *expr, char const *str) noexcept; +bool wild_match(char const *expr, char const *str) noexcept; #endif // OSM2PGSQL_WILDCMP_HPP diff --git a/tests/test-wildcard-match.cpp b/tests/test-wildcard-match.cpp index 0676d23c4..b7d82cef1 100644 --- a/tests/test-wildcard-match.cpp +++ b/tests/test-wildcard-match.cpp @@ -13,31 +13,31 @@ TEST_CASE("Wildcard matching", "[NoDB]") { - CHECK(wildMatch("fhwieurwe", "fhwieurwe")); - CHECK_FALSE(wildMatch("fhwieurwe", "fhwieurw")); - CHECK_FALSE(wildMatch("fhwieurw", "fhwieurwe")); - CHECK(wildMatch("*", "foo")); - CHECK(wildMatch("**", "foo")); - CHECK_FALSE(wildMatch("r*", "foo")); - CHECK(wildMatch("r*", "roo")); - CHECK(wildMatch("*bar", "Hausbar")); - CHECK_FALSE(wildMatch("*bar", "Haustar")); - CHECK(wildMatch("*", "")); - CHECK(wildMatch("**", "")); - CHECK(wildMatch("kin*la", "kinla")); - CHECK(wildMatch("kin*la", "kinLLla")); - CHECK(wildMatch("kin*la", "kinlalalala")); - CHECK(wildMatch("kin**la", "kinlalalala")); - CHECK_FALSE(wildMatch("kin*la", "kinlaa")); - CHECK_FALSE(wildMatch("kin*la", "ki??laa")); - CHECK(wildMatch("1*2*3", "123")); - CHECK(wildMatch("1*2*3", "1xX23")); - CHECK(wildMatch("1*2*3", "12y23")); - CHECK_FALSE(wildMatch("1*2*3", "12")); - CHECK(wildMatch("bo??f", "boxxf")); - CHECK_FALSE(wildMatch("bo??f", "boxf")); - CHECK(wildMatch("?5?", "?5?")); - CHECK(wildMatch("?5?", "x5x")); - CHECK_FALSE(wildMatch("?abc", "")); - CHECK_FALSE(wildMatch("?", "")); + CHECK(wild_match("fhwieurwe", "fhwieurwe")); + CHECK_FALSE(wild_match("fhwieurwe", "fhwieurw")); + CHECK_FALSE(wild_match("fhwieurw", "fhwieurwe")); + CHECK(wild_match("*", "foo")); + CHECK(wild_match("**", "foo")); + CHECK_FALSE(wild_match("r*", "foo")); + CHECK(wild_match("r*", "roo")); + CHECK(wild_match("*bar", "Hausbar")); + CHECK_FALSE(wild_match("*bar", "Haustar")); + CHECK(wild_match("*", "")); + CHECK(wild_match("**", "")); + CHECK(wild_match("kin*la", "kinla")); + CHECK(wild_match("kin*la", "kinLLla")); + CHECK(wild_match("kin*la", "kinlalalala")); + CHECK(wild_match("kin**la", "kinlalalala")); + CHECK_FALSE(wild_match("kin*la", "kinlaa")); + CHECK_FALSE(wild_match("kin*la", "ki??laa")); + CHECK(wild_match("1*2*3", "123")); + CHECK(wild_match("1*2*3", "1xX23")); + CHECK(wild_match("1*2*3", "12y23")); + CHECK_FALSE(wild_match("1*2*3", "12")); + CHECK(wild_match("bo??f", "boxxf")); + CHECK_FALSE(wild_match("bo??f", "boxf")); + CHECK(wild_match("?5?", "?5?")); + CHECK(wild_match("?5?", "x5x")); + CHECK_FALSE(wild_match("?abc", "")); + CHECK_FALSE(wild_match("?", "")); }