Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1356,6 +1356,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
if (std::strcmp(engine, "pcre") == 0) {
rule.engine = Regex::Engine::Pcre;
}
else if (std::strcmp(engine, "std") == 0) {
rule.engine = Regex::Engine::Std;
}
else {
mLogger.printError(std::string("unknown regex engine '") + engine + "'.");
return Result::Fail;
Expand Down
48 changes: 48 additions & 0 deletions lib/regex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "regex.h"

#include <regex>
#include <utility>

#ifdef _WIN32
Expand Down Expand Up @@ -246,6 +247,51 @@ namespace {
}
}

namespace {
class StdRegex : public Regex
{
public:
explicit StdRegex(std::string pattern)
: mPattern(std::move(pattern))
{}

std::string compile()
{
if (mCompiled)
return "regular expression has already been compiled";

try {
mRegex = std::regex(mPattern);
} catch (const std::exception& e) {
return e.what();
}
mCompiled = true;
return "";
}

std::string match(const std::string& str, const MatchFn& matchFn) const override
{
if (!mCompiled)
return "regular expression has not been compiled yet";

auto I = std::sregex_iterator(str.cbegin(), str.cend(), mRegex);
const auto E = std::sregex_iterator();
while (I != E)
{
const std::smatch& match = *I;
matchFn(match.position(), match.position() + match.length());
++I;
}
return "";
}

private:
std::string mPattern;
std::regex mRegex;
bool mCompiled{};
};
}

template<typename T>
static T* createAndCompileRegex(std::string pattern, std::string& err)
{
Expand All @@ -259,6 +305,8 @@ std::shared_ptr<Regex> Regex::create(std::string pattern, Engine engine, std::st
Regex* regex = nullptr;
if (engine == Engine::Pcre)
regex = createAndCompileRegex<PcreRegex>(std::move(pattern), err);
else if (engine == Engine::Std)
regex = createAndCompileRegex<StdRegex>(std::move(pattern), err);
else {
err = "unknown regular expression engine";
}
Expand Down
3 changes: 2 additions & 1 deletion lib/regex.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class CPPCHECKLIB Regex
enum class Engine : std::uint8_t
{
Unknown = 0,
Pcre = 1
Pcre = 1,
Std = 2
};

static std::shared_ptr<Regex> create(std::string pattern, Engine engine, std::string& err);
Expand Down
2 changes: 2 additions & 0 deletions releasenotes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ Infrastructure & dependencies:

Other:
- Make it possible to specify the regular expression engine using the `engine` element in a rule XML.
- Added support for `std::regex` as the regular engine for rules. It can be specified using `std` in the engine` element in a rule XML.
-
3 changes: 2 additions & 1 deletion test/testcmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2674,6 +2674,7 @@ class TestCmdlineParser : public TestFixture {
"</message>\n"
"</rule>\n"
"<rule>\n"
"<engine>std</engine>\n"
"<tokenlist>define</tokenlist>\n"
"<pattern>.*</pattern>\n"
"<message>\n"
Expand All @@ -2694,7 +2695,7 @@ class TestCmdlineParser : public TestFixture {
ASSERT_EQUALS("ruleId1", it->id);
ASSERT_EQUALS("ruleSummary1", it->summary);
++it;
ASSERT_EQUALS_ENUM(Regex::Engine::Pcre, it->engine);
ASSERT_EQUALS_ENUM(Regex::Engine::Std, it->engine);
ASSERT_EQUALS("define", it->tokenlist);
ASSERT_EQUALS(".*", it->pattern);
ASSERT_EQUALS_ENUM(Severity::warning, it->severity);
Expand Down
18 changes: 18 additions & 0 deletions test/testregex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ class TestRegExBase : public TestFixture {
std::string exp;
if (mEngine == Regex::Engine::Pcre)
exp = "missing terminating ] for character class";
else if (mEngine == Regex::Engine::Std)
{
#if defined(_MSC_VER)
exp = "regex_error(error_brack): The expression contained mismatched [ and ].";
#elif defined(_LIBCPP_VERSION)
exp = "The expression contained mismatched [ and ].";
#elif defined(__clang__)
exp = "Unexpected character within '[...]' in regular expression";
#else
exp = "Unexpected character in bracket expression.";
#endif
}

(void)assertRegex("[", exp);
}
Expand Down Expand Up @@ -201,6 +213,12 @@ class TestRegExPcre : public TestRegExBase {
TestRegExPcre() : TestRegExBase("TestRegExPcre", Regex::Engine::Pcre) {}
};

class TestRegExStd : public TestRegExBase {
public:
TestRegExStd() : TestRegExBase("TestRegExStd", Regex::Engine::Std) {}
};

REGISTER_TEST(TestRegExPcre)
REGISTER_TEST(TestRegExStd)

#endif // HAVE_RULES