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
258 changes: 129 additions & 129 deletions Makefile

Large diffs are not rendered by default.

17 changes: 15 additions & 2 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}

std::string regex_err;
auto regex = Regex::create(rule.pattern, regex_err);
auto regex = Regex::create(rule.pattern, Regex::Engine::Pcre, regex_err);
if (!regex) {
mLogger.printError("failed to compile rule pattern '" + rule.pattern + "' (" + regex_err + ").");
return Result::Fail;
Expand Down Expand Up @@ -1350,6 +1350,19 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}
}
}
else if (std::strcmp(subname, "engine") == 0) {
const char * const engine = empty_if_null(subtext);
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;
}
}
else {
mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + subname + "' encountered in 'rule'.");
return Result::Fail;
Expand Down Expand Up @@ -1377,7 +1390,7 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
}

std::string regex_err;
auto regex = Regex::create(rule.pattern, regex_err);
auto regex = Regex::create(rule.pattern, rule.engine, regex_err);
if (!regex) {
mLogger.printError("unable to load rule-file '" + ruleFile + "' - pattern '" + rule.pattern + "' failed to compile (" + regex_err + ").");
return Result::Fail;
Expand Down
76 changes: 68 additions & 8 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 @@ -188,15 +189,15 @@ namespace {
std::string PcreRegex::compile()
{
if (mRe)
return "pcre_compile failed: regular expression has already been compiled";
return "regular expression has already been compiled";

const char *pcreCompileErrorStr = nullptr;
int erroffset = 0;
pcre * const re = pcre_compile(mPattern.c_str(),0,&pcreCompileErrorStr,&erroffset,nullptr);
if (!re) {
if (pcreCompileErrorStr)
return "pcre_compile failed: " + std::string(pcreCompileErrorStr);
return "pcre_compile failed: unknown error";
return pcreCompileErrorStr;
return "unknown error";
}

// Optimize the regex, but only if PCRE_CONFIG_JIT is available
Expand All @@ -209,7 +210,7 @@ namespace {
if (pcreStudyErrorStr) {
// pcre_compile() worked, but pcre_study() returned an error. Free the resources allocated by pcre_compile().
pcre_free(re);
return "pcre_study failed: " + std::string(pcreStudyErrorStr);
return std::string(pcreStudyErrorStr) + " (pcre_study)";
}
mExtra = pcreExtra;
#endif
Expand All @@ -222,7 +223,7 @@ namespace {
std::string PcreRegex::match(const std::string& str, const MatchFn& match) const
{
if (!mRe)
return "pcre_exec failed: regular expression has not been compiled yet";
return "regular expression has not been compiled yet";

int pos = 0;
int ovector[30]= {0};
Expand All @@ -231,7 +232,7 @@ namespace {
if (pcreExecRet == PCRE_ERROR_NOMATCH)
return "";
if (pcreExecRet < 0) {
return "pcre_exec failed (pos: " + std::to_string(pos) + "): " + pcreErrorCodeToString(pcreExecRet);
return pcreErrorCodeToString(pcreExecRet) + " (pos: " + std::to_string(pos) + ")";
}
const auto pos1 = static_cast<unsigned int>(ovector[0]);
const auto pos2 = static_cast<unsigned int>(ovector[1]);
Expand All @@ -246,10 +247,69 @@ namespace {
}
}

std::shared_ptr<Regex> Regex::create(std::string pattern, std::string& err)
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)
{
auto* regex = new PcreRegex(std::move(pattern));
T* regex = new T(std::move(pattern));
err = regex->compile();
return regex;
}

std::shared_ptr<Regex> Regex::create(std::string pattern, Engine engine, std::string& err)
{
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";
}
if (!err.empty()) {
delete regex;
return nullptr;
Expand Down
10 changes: 9 additions & 1 deletion lib/regex.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "config.h"

#include <cstdint>
#include <functional>
#include <memory>
#include <string>
Expand All @@ -37,7 +38,14 @@ class CPPCHECKLIB Regex
using MatchFn = std::function<void (int start, int end)>;
virtual std::string match(const std::string& str, const MatchFn& matchFn) const = 0;

static std::shared_ptr<Regex> create(std::string pattern, std::string& err);
enum class Engine : std::uint8_t
{
Unknown = 0,
Pcre = 1,
Std = 2
};

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

#endif // HAVE_RULES
Expand Down
3 changes: 3 additions & 0 deletions lib/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include <unordered_set>
#include <utility>

#include "regex.h"

#if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
#include <cstdio>
#endif
Expand Down Expand Up @@ -347,6 +349,7 @@ class CPPCHECKLIB WARN_UNUSED Settings {
std::string id = "rule"; // default id
std::string summary;
Severity severity = Severity::style; // default severity
Regex::Engine engine = Regex::Engine::Pcre;
std::shared_ptr<Regex> regex;
};

Expand Down
Loading
Loading