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
10 changes: 10 additions & 0 deletions cli/cmdlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,9 @@ CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const a
#ifdef HAVE_RULES
Settings::Rule rule;
rule.pattern = 7 + argv[i];
#if defined(HAVE_PCRE2) && !defined(HAVE_PCRE)
rule.engine = Regex::Engine::Pcre2;
#endif

if (rule.pattern.empty()) {
mLogger.printError("no rule pattern provided.");
Expand Down Expand Up @@ -1357,9 +1360,16 @@ 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);
#ifdef HAVE_PCRE
if (std::strcmp(engine, "pcre") == 0) {
rule.engine = Regex::Engine::Pcre;
}
#endif
#ifdef HAVE_PCRE2
else if (std::strcmp(engine, "pcre2") == 0) {
rule.engine = Regex::Engine::Pcre2;
}
#endif
else {
mLogger.printError(std::string("unknown regex engine '") + engine + "'.");
return Result::Fail;
Expand Down
6 changes: 6 additions & 0 deletions cmake/compilerDefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ endif()

if(HAVE_RULES)
add_definitions(-DHAVE_RULES)
if(USE_PCRE2)
add_definitions(-DHAVE_PCRE2)
endif()
if(NOT DISABLE_PCRE1)
add_definitions(-DHAVE_PCRE)
endif()
endif()

if(Boost_FOUND)
Expand Down
17 changes: 13 additions & 4 deletions cmake/findDependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@ if(BUILD_GUI)
endif()

if(HAVE_RULES)
find_path(PCRE_INCLUDE pcre.h)
find_library(PCRE_LIBRARY NAMES pcre pcred)
if(NOT PCRE_LIBRARY OR NOT PCRE_INCLUDE)
message(FATAL_ERROR "pcre dependency for RULES has not been found")
if(USE_PCRE2)
find_path(PCRE2_INCLUDE pcre2.h)
find_library(PCRE2_LIBRARY NAMES pcre2-8) # TODO: is this the proper library?
if(NOT PCRE2_LIBRARY OR NOT PCRE2_INCLUDE)
message(FATAL_ERROR "PCRE2 dependency for rules has not been found")
endif()
endif()
if(NOT DISABLE_PCRE1)
find_path(PCRE_INCLUDE pcre.h)
find_library(PCRE_LIBRARY NAMES pcre pcred)
if(NOT PCRE_LIBRARY OR NOT PCRE_INCLUDE)
message(FATAL_ERROR "PCRE dependency for rules has not been found")
endif()
endif()
else()
set(PCRE_LIBRARY "")
Expand Down
11 changes: 11 additions & 0 deletions cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@ if(NOT BUILD_GUI)
endif()

option(HAVE_RULES "Usage of rules (needs PCRE library and headers)" OFF)
option(USE_PCRE2 "Usage of PCRE2 for rules" OFF)
if(NOT HAVE_RULES AND USE_PCRE2)
message(AUTHOR_WARNING "USE_PCRE2 has no effect without HAVE_RULES")
endif()
option(DISABLE_PCRE1 "Disable usage of PCRE1 for rules" OFF)
if(NOT HAVE_RULES AND DISABLE_PCRE1)
message(AUTHOR_WARNING "DISABLE_PCRE1 has no effect without HAVE_RULES")
endif()
if(HAVE_RULES AND DISABLE_PCRE1 AND NOT USE_PCRE2)
message(FATAL_ERROR "No regular expression engine enabled")
endif()
option(USE_BUNDLED_TINYXML2 "Usage of bundled TinyXML2 library" ON)
if(BUILD_CORE_DLL AND NOT USE_BUNDLED_TINYXML2)
message(FATAL_ERROR "Cannot use external TinyXML2 library when building lib as DLL")
Expand Down
11 changes: 10 additions & 1 deletion cmake/printInfo.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,16 @@ endif()
message(STATUS)
message(STATUS "HAVE_RULES = ${HAVE_RULES}")
if(HAVE_RULES)
message(STATUS "PCRE_LIBRARY = ${PCRE_LIBRARY}")
message(STATUS "USE_PCRE2 = ${USE_PCRE2}")
message(STATUS "DISABLE_PCRE1 = ${DISABLE_PCRE1}")
if(USE_PCRE2)
message(STATUS "PCRE2_INCLUDE = ${PCRE2_INCLUDE}")
message(STATUS "PCRE2_LIBRARY = ${PCRE2_LIBRARY}")
endif()
if(NOT DISABLE_PCRE1)
message(STATUS "PCRE_INCLUDE = ${PCRE_INCLUDE}")
message(STATUS "PCRE_LIBRARY = ${PCRE_LIBRARY}")
endif()
endif()
message(STATUS)
message(STATUS "DISALLOW_THREAD_EXECUTOR = ${DISALLOW_THREAD_EXECUTOR}")
Expand Down
7 changes: 6 additions & 1 deletion gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ CheckOptions:
target_precompile_headers(cppcheck-gui PRIVATE precompiled.h)
endif()
if (HAVE_RULES)
target_link_libraries(cppcheck-gui ${PCRE_LIBRARY})
if(USE_PCRE2)
target_link_libraries(cppcheck-gui ${PCRE2_LIBRARY})
endif()
if(NOT DISABLE_PCRE1)
target_link_libraries(cppcheck-gui ${PCRE_LIBRARY})
endif()
endif()
target_link_libraries(cppcheck-gui ${QT_CORE_LIB} ${QT_GUI_LIB} ${QT_WIDGETS_LIB} ${QT_PRINTSUPPORT_LIB} ${QT_HELP_LIB} ${QT_NETWORK_LIB})
if(WITH_QCHART)
Expand Down
10 changes: 8 additions & 2 deletions gui/test/resultstree/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ add_executable(test-resultstree
target_include_directories(test-resultstree PRIVATE ${CMAKE_SOURCE_DIR}/gui)
target_link_libraries(test-resultstree cppcheck-core simplecpp tinyxml2)
if (HAVE_RULES)
target_link_libraries(test-resultstree ${PCRE_LIBRARY})
target_include_directories(test-resultstree SYSTEM PRIVATE ${PCRE_INCLUDE})
if(USE_PCRE2)
target_link_libraries(test-resultstree ${PCRE2_LIBRARY})
target_include_directories(test-resultstree SYSTEM PRIVATE ${PCRE2_INCLUDE})
endif()
if(NOT DISABLE_CPRE1)
target_link_libraries(test-resultstree ${PCRE_LIBRARY})
target_include_directories(test-resultstree SYSTEM PRIVATE ${PCRE_INCLUDE})
endif()
endif()
target_compile_definitions(test-resultstree PRIVATE SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(test-resultstree ${QT_CORE_LIB} ${QT_GUI_LIB} ${QT_WIDGETS_LIB} ${QT_TEST_LIB})
Expand Down
17 changes: 15 additions & 2 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,23 @@ endif()
target_dll_compile_definitions(cppcheck-core EXPORT CPPCHECKLIB_EXPORT IMPORT CPPCHECKLIB_IMPORT)

target_include_directories(cppcheck-core PUBLIC .)
target_link_libraries(cppcheck-core PRIVATE tinyxml2 simplecpp picojson ${PCRE_LIBRARY})
target_link_libraries(cppcheck-core PRIVATE tinyxml2 simplecpp picojson)
if (HAVE_RULES)
if(USE_PCRE2)
target_link_libraries(cppcheck-core PRIVATE ${PCRE2_LIBRARY})
endif()
if(NOT DISABLE_PCRE1)
target_link_libraries(cppcheck-core PRIVATE ${PCRE_LIBRARY})
endif()
endif()

if (HAVE_RULES)
target_include_directories(cppcheck-core SYSTEM PRIVATE ${PCRE_INCLUDE})
if(USE_PCRE2)
target_include_directories(cppcheck-core SYSTEM PRIVATE ${PCRE2_INCLUDE})
endif()
if(NOT DISABLE_PCRE1)
target_include_directories(cppcheck-core SYSTEM PRIVATE ${PCRE_INCLUDE})
endif()
endif()
if (Boost_FOUND)
target_include_directories(cppcheck-core SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
Expand Down
158 changes: 128 additions & 30 deletions lib/regex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,51 @@

#include <utility>

#ifdef HAVE_PCRE
#ifdef _WIN32
#define PCRE_STATIC
#endif
#include <pcre.h>
#endif

#ifdef HAVE_PCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#endif

#ifdef HAVE_PCRE
namespace {
std::string pcreErrorCodeToString(const int pcreExecRet)
class PcreRegex : public Regex
{
public:
explicit PcreRegex(std::string pattern)
: mPattern(std::move(pattern))
{}

~PcreRegex() override
{
if (mExtra) {
pcre_free_study(mExtra);
mExtra = nullptr;
}
if (mRe) {
pcre_free(mRe);
mRe = nullptr;
}
}

std::string compile();
std::string match(const std::string& str, const MatchFn& match) const override;

private:
static std::string pcreErrorCodeToString(int pcreExecRet);

std::string mPattern;
pcre* mRe{};
pcre_extra* mExtra{};
};

std::string PcreRegex::pcreErrorCodeToString(const int pcreExecRet)
{
switch (pcreExecRet) {
case PCRE_ERROR_NULL:
Expand Down Expand Up @@ -157,34 +195,6 @@ namespace {
return "unknown PCRE error " + std::to_string(pcreExecRet);
}

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

~PcreRegex() override
{
if (mExtra) {
pcre_free_study(mExtra);
mExtra = nullptr;
}
if (mRe) {
pcre_free(mRe);
mRe = nullptr;
}
}

std::string compile();
std::string match(const std::string& str, const MatchFn& match) const override;

private:
std::string mPattern;
pcre* mRe{};
pcre_extra* mExtra{};
};

std::string PcreRegex::compile()
{
if (mRe)
Expand Down Expand Up @@ -245,6 +255,88 @@ namespace {
return "";
}
}
#endif // HAVE_PCRE

#ifdef HAVE_PCRE2
namespace {
class Pcre2Regex : public Regex
{
public:
explicit Pcre2Regex(std::string pattern)
: mPattern(std::move(pattern))
{}

~Pcre2Regex() override
{
if (mRe) {
pcre_free(mRe);
mRe = nullptr;
}
}

std::string compile();
std::string match(const std::string& str, const MatchFn& match) const override;

private:
std::string mPattern;
pcre2_code* mRe{};
};

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

int errnumber = 0;
size_t erroffset = 0;
pcre2_code * const re = pcre2_compile(reinterpret_cast<PCRE2_SPTR8>(mPattern.c_str()), PCRE2_ZERO_TERMINATED, 0, &errnumber, &erroffset, nullptr);
if (!re) {
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errnumber, buffer, sizeof(buffer));
return reinterpret_cast<char*>(buffer);
}

mRe = re;

return "";
}

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

pcre2_match_data* match_data = pcre2_match_data_create_from_pattern(mRe, NULL);

int pos = 0;
while (pos < static_cast<int>(str.size())) {
const int pcreExecRet = pcre2_match(mRe, reinterpret_cast<PCRE2_SPTR8>(str.c_str()), static_cast<int>(str.size()), pos, 0, match_data, nullptr);
if (pcreExecRet == PCRE2_ERROR_NOMATCH)
return "";
if (pcreExecRet < 0) {
PCRE2_UCHAR errorMessageBuf[120];
const int res = pcre2_get_error_message(pcreExecRet, errorMessageBuf, sizeof(errorMessageBuf));
if (res < 0)
return std::string("failed to get error message ") + std::to_string(res) + " (pos: " + std::to_string(pos) + ")";
return std::string(reinterpret_cast<char*>(errorMessageBuf)) + " (pos: " + std::to_string(pos) + ")";
}
PCRE2_SIZE* ovector = pcre2_get_ovector_pointer(match_data);
const uint32_t ovcount = pcre2_get_ovector_count(match_data);
if (ovcount != 1)
return "invalid ovector count";
const auto pos1 = static_cast<unsigned int>(ovector[0]);
const auto pos2 = static_cast<unsigned int>(ovector[1]);

match(pos1, pos2);

// jump to the end of the match for the next pcre_exec
pos = static_cast<int>(pos2);
}

return "";
}
}
#endif // HAVE_PCRE2

template<typename T>
static T* createAndCompileRegex(std::string pattern, std::string& err)
Expand All @@ -257,9 +349,15 @@ static T* createAndCompileRegex(std::string pattern, std::string& err)
std::shared_ptr<Regex> Regex::create(std::string pattern, Engine engine, std::string& err)
{
Regex* regex = nullptr;
#ifdef HAVE_PCRE
if (engine == Engine::Pcre)
regex = createAndCompileRegex<PcreRegex>(std::move(pattern), err);
else {
#endif
#ifdef HAVE_PCRE2
if (engine == Engine::Pcre2)
regex = createAndCompileRegex<Pcre2Regex>(std::move(pattern), err);
#endif
if (!regex) {
err = "unknown regular expression engine";
}
if (!err.empty()) {
Expand Down
7 changes: 6 additions & 1 deletion lib/regex.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@ class CPPCHECKLIB Regex
enum class Engine : std::uint8_t
{
Unknown = 0,
Pcre = 1
#ifdef HAVE_PCRE
Pcre = 1,
#endif
#ifdef HAVE_PCRE2
Pcre2 = 2
#endif
};

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

Other:
- Make it possible to specify the regular expression engine using the `engine` element in a rule XML.
- Added support for PCRE2 (`pcre2`) as the regular expression engine for rules.
- Added CMake option `USE_PCRE2` to enable usage of the PCRE2 library for rules (will not change the default).
- Added CMake option `DISABLE_PCRE1` to disable usage of the PCRE library for rules (changes default to `pcre2`).
-
-
Loading