Skip to content

Commit 4b16f58

Browse files
committed
fixed #14261 - Regex: added std::regex implementation [skip ci]
1 parent 9305216 commit 4b16f58

6 files changed

Lines changed: 75 additions & 2 deletions

File tree

cli/cmdlineparser.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
13651365
if (std::strcmp(engine, "pcre") == 0) {
13661366
rule.engine = Regex::Engine::Pcre;
13671367
}
1368+
else if (std::strcmp(engine, "std") == 0) {
1369+
rule.engine = Regex::Engine::Std;
1370+
}
13681371
else {
13691372
mLogger.printError(std::string("unknown regex engine '") + engine + "'.");
13701373
return Result::Fail;

lib/regex.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "regex.h"
2222

23+
#include <regex>
2324
#include <utility>
2425

2526
#ifdef _WIN32
@@ -246,6 +247,51 @@ namespace {
246247
}
247248
}
248249

250+
namespace {
251+
class StdRegex : public Regex
252+
{
253+
public:
254+
explicit StdRegex(std::string pattern)
255+
: mPattern(std::move(pattern))
256+
{}
257+
258+
std::string compile()
259+
{
260+
if (mCompiled)
261+
return "regular expression has already been compiled";
262+
263+
try {
264+
mRegex = std::regex(mPattern);
265+
} catch (const std::exception& e) {
266+
return e.what();
267+
}
268+
mCompiled = true;
269+
return "";
270+
}
271+
272+
std::string match(const std::string& str, const MatchFn& matchFn) const override
273+
{
274+
if (!mCompiled)
275+
return "regular expression has not been compiled yet";
276+
277+
auto I = std::sregex_iterator(str.cbegin(), str.cend(), mRegex);
278+
const auto E = std::sregex_iterator();
279+
while (I != E)
280+
{
281+
const std::smatch& match = *I;
282+
matchFn(match.position(), match.position() + match.length());
283+
++I;
284+
}
285+
return "";
286+
}
287+
288+
private:
289+
std::string mPattern;
290+
std::regex mRegex;
291+
bool mCompiled{};
292+
};
293+
}
294+
249295
template<typename T>
250296
static T* createAndCompileRegex(std::string pattern, std::string& err)
251297
{
@@ -259,6 +305,8 @@ std::shared_ptr<Regex> Regex::create(std::string pattern, Engine engine, std::st
259305
Regex* regex = nullptr;
260306
if (engine == Engine::Pcre)
261307
regex = createAndCompileRegex<PcreRegex>(std::move(pattern), err);
308+
else if (engine == Engine::Std)
309+
regex = createAndCompileRegex<StdRegex>(std::move(pattern), err);
262310
else {
263311
err = "unknown regular expression engine";
264312
}

lib/regex.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ class CPPCHECKLIB Regex
4141
enum class Engine : std::uint8_t
4242
{
4343
Unknown = 0,
44-
Pcre = 1
44+
Pcre = 1,
45+
Std = 2
4546
};
4647

4748
static std::shared_ptr<Regex> create(std::string pattern, Engine engine, std::string& err);

releasenotes.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ Other:
2525
- Make it possible to specify the regular expression engine using the `engine` element in a rule XML.
2626
- Added CLI option `--exitcode-suppress` to specify an error ID which should not result in a non-zero exitcode.
2727
- Moved source code from https://github.com/danmar/cppcheck to https://github.com/cppcheck-opensource/cppcheck
28+
- 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.
29+
-
2830
-

test/testcmdlineparser.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2706,6 +2706,7 @@ class TestCmdlineParser : public TestFixture {
27062706
"</message>\n"
27072707
"</rule>\n"
27082708
"<rule>\n"
2709+
"<engine>std</engine>\n"
27092710
"<tokenlist>define</tokenlist>\n"
27102711
"<pattern>.*</pattern>\n"
27112712
"<message>\n"
@@ -2726,7 +2727,7 @@ class TestCmdlineParser : public TestFixture {
27262727
ASSERT_EQUALS("ruleId1", it->id);
27272728
ASSERT_EQUALS("ruleSummary1", it->summary);
27282729
++it;
2729-
ASSERT_EQUALS_ENUM(Regex::Engine::Pcre, it->engine);
2730+
ASSERT_EQUALS_ENUM(Regex::Engine::Std, it->engine);
27302731
ASSERT_EQUALS("define", it->tokenlist);
27312732
ASSERT_EQUALS(".*", it->pattern);
27322733
ASSERT_EQUALS_ENUM(Severity::warning, it->severity);

test/testregex.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ class TestRegExBase : public TestFixture {
8585
std::string exp;
8686
if (mEngine == Regex::Engine::Pcre)
8787
exp = "missing terminating ] for character class";
88+
else if (mEngine == Regex::Engine::Std)
89+
{
90+
#if defined(_MSC_VER)
91+
exp = "regex_error(error_brack): The expression contained mismatched [ and ].";
92+
#elif defined(_LIBCPP_VERSION)
93+
exp = "The expression contained mismatched [ and ].";
94+
#elif defined(__clang__)
95+
exp = "Unexpected character within '[...]' in regular expression";
96+
#else
97+
exp = "Unexpected character in bracket expression.";
98+
#endif
99+
}
88100

89101
(void)assertRegex("[", exp);
90102
}
@@ -201,6 +213,12 @@ class TestRegExPcre : public TestRegExBase {
201213
TestRegExPcre() : TestRegExBase("TestRegExPcre", Regex::Engine::Pcre) {}
202214
};
203215

216+
class TestRegExStd : public TestRegExBase {
217+
public:
218+
TestRegExStd() : TestRegExBase("TestRegExStd", Regex::Engine::Std) {}
219+
};
220+
204221
REGISTER_TEST(TestRegExPcre)
222+
REGISTER_TEST(TestRegExStd)
205223

206224
#endif // HAVE_RULES

0 commit comments

Comments
 (0)