Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support PCRE2 #13771

Merged
merged 1 commit into from
May 21, 2024
Merged
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
1 change: 1 addition & 0 deletions bindings/pyroot/pythonizations/test/import_load_libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class ImportLoadLibs(unittest.TestCase):
'libc',
'libdl',
'libpcre',
'libpcre2-8',
# libCling and dependencies
'libCling.*',
'librt',
Expand Down
106 changes: 106 additions & 0 deletions cmake/modules/FindPCRE2.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.
# All rights reserved.
#
# For the licensing terms see $ROOTSYS/LICENSE.
# For the list of contributors see $ROOTSYS/README/CREDITS.

#.rst:
# FindPCRE2
# --------
#
# Find PCRE2 library
#
# Imported Targets
# ^^^^^^^^^^^^^^^^
#
# This module defines :prop_tgt:`IMPORTED` target:
#
# ``PCRE2::PCRE2``
# The pcre2 library, if found.
#
# Result Variables
# ^^^^^^^^^^^^^^^^
# This module will set the following variables in your project:
#
# ``PCRE2_FOUND``
# True if PCRE2 has been found.
# ``PCRE2_INCLUDE_DIRS``
# Where to find pcre2.h
# ``PCRE2_LIBRARIES``
# The libraries to link against to use PCRE2.
# ``PCRE2_VERSION``
# The version of the PCRE2 found (e.g. 10.42)
#
# Obsolete variables
# ^^^^^^^^^^^^^^^^^^
#
# The following variables may also be set, for backwards compatibility:
#
# ``PCRE2_PCRE2_LIBRARY``
# where to find the PCRE2_PCRE2 library.
# ``PCRE2_INCLUDE_DIR``
# where to find the pcre2.h header (same as PCRE2_INCLUDE_DIRS)
#

foreach(var PCRE2_FOUND PCRE2_INCLUDE_DIR PCRE2_PCRE2_LIBRARY PCRE2_LIBRARIES)
unset(${var} CACHE)
endforeach()

find_path(PCRE2_INCLUDE_DIR NAMES pcre2.h PATH_SUFFIXES include)
mark_as_advanced(PCRE2_INCLUDE_DIR)

if (PCRE2_INCLUDE_DIR AND EXISTS "${PCRE2_INCLUDE_DIR}/pcre2.h")
file(STRINGS "${PCRE2_INCLUDE_DIR}/pcre2.h" PCRE2_H REGEX "^#define PCRE2_(MAJOR|MINOR).*$")
string(REGEX REPLACE "^.*PCRE2_MAJOR[ ]+([0-9]+).*$" "\\1" PCRE2_VERSION_MAJOR "${PCRE2_H}")
string(REGEX REPLACE "^.*PCRE2_MINOR[ ]+([0-9]+).*$" "\\1" PCRE2_VERSION_MINOR "${PCRE2_H}")
set(PCRE2_VERSION "${PCRE2_VERSION_MAJOR}.${PCRE2_VERSION_MINOR}")
endif()

if(NOT PCRE2_PCRE2_LIBRARY)
find_library(PCRE2_PCRE2_LIBRARY_RELEASE NAMES pcre2-8)
find_library(PCRE2_PCRE2_LIBRARY_DEBUG NAMES pcre2-8${CMAKE_DEBUG_POSTFIX} pcre2-8d)
include(SelectLibraryConfigurations)
select_library_configurations(PCRE2_PCRE2)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PCRE2
REQUIRED_VARS
PCRE2_INCLUDE_DIR
PCRE2_PCRE2_LIBRARY
VERSION_VAR
PCRE2_VERSION
)

if(PCRE2_FOUND)
set(PCRE2_INCLUDE_DIRS "${PCRE2_INCLUDE_DIR}")

if (NOT PCRE2_LIBRARIES)
set(PCRE2_LIBRARIES "${PCRE2_PCRE2_LIBRARY}")
endif()

if(NOT TARGET PCRE2::PCRE2)
add_library(PCRE2::PCRE2 UNKNOWN IMPORTED)
set_target_properties(PCRE2::PCRE2 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${PCRE2_INCLUDE_DIRS}")

if(PCRE2_PCRE2_LIBRARY_DEBUG)
set_property(TARGET PCRE2::PCRE2 APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(PCRE2::PCRE2 PROPERTIES
IMPORTED_LOCATION_DEBUG "${PCRE2_PCRE2_LIBRARY_DEBUG}")
endif()

if(PCRE2_PCRE2_LIBRARY_RELEASE)
set_property(TARGET PCRE2::PCRE2 APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(PCRE2::PCRE2 PROPERTIES
IMPORTED_LOCATION_RELEASE "${PCRE2_PCRE2_LIBRARY_RELEASE}")
endif()

if(NOT PCRE2_PCRE2_LIBRARY_DEBUG AND NOT PCRE2_PCRE2_LIBRARY_RELEASE)
set_property(TARGET PCRE2::PCRE2 APPEND PROPERTY
IMPORTED_LOCATION "${PCRE2_PCRE2_LIBRARY}")
endif()
endif()
endif()
17 changes: 10 additions & 7 deletions cmake/modules/SearchInstalledSoftware.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,16 @@ if(NOT builtin_pcre)
foreach(suffix FOUND INCLUDE_DIR PCRE_LIBRARY)
unset(PCRE_${suffix} CACHE)
endforeach()
if(fail-on-missing)
find_package(PCRE REQUIRED)
else()
find_package(PCRE)
if(NOT PCRE_FOUND)
message(STATUS "PCRE not found. Switching on builtin_pcre option")
set(builtin_pcre ON CACHE BOOL "Enabled because PCRE not found (${builtin_pcre_description})" FORCE)
find_package(PCRE2)
if(NOT PCRE2_FOUND)
if(fail-on-missing)
find_package(PCRE REQUIRED)
else()
find_package(PCRE)
if(NOT PCRE_FOUND)
message(STATUS "PCRE not found. Switching on builtin_pcre option")
set(builtin_pcre ON CACHE BOOL "Enabled because PCRE not found (${builtin_pcre_description})" FORCE)
endif()
endif()
endif()
endif()
Expand Down
9 changes: 8 additions & 1 deletion core/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,14 @@ target_include_directories(Core PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/v7/inc>
)

target_link_libraries(Core PRIVATE PCRE::PCRE)
if(PCRE2_FOUND)
target_link_libraries(Core PRIVATE PCRE2::PCRE2)
set_source_files_properties(src/TPRegexp.cxx
TARGET_DIRECTORY Core
PROPERTIES COMPILE_DEFINITIONS USE_PCRE2)
else()
target_link_libraries(Core PRIVATE PCRE::PCRE)
endif()

ROOT_INSTALL_HEADERS(${BASE_HEADER_DIRS})

Expand Down
99 changes: 95 additions & 4 deletions core/base/src/TPRegexp.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,36 @@ found at : http://perldoc.perl.org/perlre.html
#include "TObjString.h"
#include "TError.h"

#ifdef USE_PCRE2
#ifdef R__WIN32
#define PCRE2_STATIC
#endif
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#define PCRE_CASELESS PCRE2_CASELESS
#define PCRE_MULTILINE PCRE2_MULTILINE
#define PCRE_DOTALL PCRE2_DOTALL
#define PCRE_EXTENDED PCRE2_EXTENDED
#define PCRE_ERROR_NOMATCH PCRE2_ERROR_NOMATCH
#else
#ifdef R__WIN32
#define PCRE_STATIC
#endif
#include <pcre.h>
#endif

#include <vector>
#include <stdexcept>

struct PCREPriv_t {
#ifdef USE_PCRE2
pcre2_code *fPCRE;
PCREPriv_t() { fPCRE = nullptr; }
#else
pcre *fPCRE;
pcre_extra *fPCREExtra;

PCREPriv_t() { fPCRE = nullptr; fPCREExtra = nullptr; }
#endif
};


Expand Down Expand Up @@ -79,10 +96,15 @@ TPRegexp::TPRegexp(const TPRegexp &p)

TPRegexp::~TPRegexp()
{
#ifdef USE_PCRE2
if (fPriv->fPCRE)
pcre2_code_free(fPriv->fPCRE);
#else
if (fPriv->fPCRE)
pcre_free(fPriv->fPCRE);
if (fPriv->fPCREExtra)
pcre_free(fPriv->fPCREExtra);
#endif
delete fPriv;
}

Expand All @@ -93,12 +115,18 @@ TPRegexp &TPRegexp::operator=(const TPRegexp &p)
{
if (this != &p) {
fPattern = p.fPattern;
#ifdef USE_PCRE2
if (fPriv->fPCRE)
pcre2_code_free(fPriv->fPCRE);
fPriv->fPCRE = nullptr;
#else
if (fPriv->fPCRE)
pcre_free(fPriv->fPCRE);
fPriv->fPCRE = nullptr;
if (fPriv->fPCREExtra)
pcre_free(fPriv->fPCREExtra);
fPriv->fPCREExtra = nullptr;
#endif
fPCREOpts = p.fPCREOpts;
}
return *this;
Expand Down Expand Up @@ -197,38 +225,58 @@ TString TPRegexp::GetModifiers() const

void TPRegexp::Compile()
{
#ifdef USE_PCRE2
if (fPriv->fPCRE)
pcre2_code_free(fPriv->fPCRE);
#else
if (fPriv->fPCRE)
pcre_free(fPriv->fPCRE);
#endif

if (fPCREOpts & kPCRE_DEBUG_MSGS)
Info("Compile", "PREGEX compiling %s", fPattern.Data());

#ifdef USE_PCRE2
int errcode;
PCRE2_SIZE patIndex;
fPriv->fPCRE = pcre2_compile((PCRE2_SPTR)fPattern.Data(), fPattern.Length(),
fPCREOpts & kPCRE_INTMASK,
&errcode, &patIndex, nullptr);
#else
const char *errstr;
Int_t patIndex;
fPriv->fPCRE = pcre_compile(fPattern.Data(), fPCREOpts & kPCRE_INTMASK,
&errstr, &patIndex, nullptr);
#endif

if (!fPriv->fPCRE) {
#ifdef USE_PCRE2
PCRE2_UCHAR errstr[256];
pcre2_get_error_message(errcode, errstr, 256);
#endif
if (fgThrowAtCompileError) {
throw std::runtime_error
(TString::Format("TPRegexp::Compile() compilation of TPRegexp(%s) failed at: %d because %s",
fPattern.Data(), patIndex, errstr).Data());
fPattern.Data(), (int)patIndex, errstr).Data());
} else {
Error("Compile", "compilation of TPRegexp(%s) failed at: %d because %s",
fPattern.Data(), patIndex, errstr);
fPattern.Data(), (int)patIndex, errstr);
return;
}
}

#ifndef USE_PCRE2
if (fPriv->fPCREExtra || (fPCREOpts & kPCRE_OPTIMIZE))
Optimize();
#endif
}

////////////////////////////////////////////////////////////////////////////////
/// Send the pattern through the optimizer.

void TPRegexp::Optimize()
{
#ifndef USE_PCRE2
if (fPriv->fPCREExtra)
pcre_free(fPriv->fPCREExtra);

Expand All @@ -243,6 +291,7 @@ void TPRegexp::Optimize()
Error("Optimize", "Optimization of TPRegexp(%s) failed: %s",
fPattern.Data(), errstr);
}
#endif
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -308,21 +357,43 @@ Int_t TPRegexp::MatchInternal(const TString &s, Int_t start,
Int_t nMaxMatch, TArrayI *pos) const
{
Int_t *offVec = new Int_t[3*nMaxMatch];

#ifdef USE_PCRE2
pcre2_match_data *match_data;
match_data = pcre2_match_data_create_from_pattern(fPriv->fPCRE, nullptr);
Int_t nrMatch = pcre2_match(fPriv->fPCRE, (PCRE2_SPTR8)s.Data(),
s.Length(), start, 0,
match_data, nullptr);
#else
// pcre_exec allows less options - see pcre_internal.h PUBLIC_EXEC_OPTIONS.
Int_t nrMatch = pcre_exec(fPriv->fPCRE, fPriv->fPCREExtra, s.Data(),
s.Length(), start, 0,
offVec, 3*nMaxMatch);
#endif

if (nrMatch == PCRE_ERROR_NOMATCH)
nrMatch = 0;
else if (nrMatch <= 0) {
Error("Match","pcre_exec error = %d", nrMatch);
#ifdef USE_PCRE2
pcre2_match_data_free(match_data);
#endif
delete [] offVec;
return 0;
}

if (pos)
if (pos) {
#ifdef USE_PCRE2
PCRE2_SIZE *oVec = pcre2_get_ovector_pointer(match_data);
for (int i = 0; i < 2 * nrMatch; ++i)
offVec[i] = oVec[i];
#endif
pos->Set(2*nrMatch, offVec);
}

#ifdef USE_PCRE2
pcre2_match_data_free(match_data);
#endif
delete [] offVec;

return nrMatch;
Expand Down Expand Up @@ -404,13 +475,24 @@ Int_t TPRegexp::SubstituteInternal(TString &s, const TString &replacePattern,
Int_t offset = start;
Int_t last = 0;

#ifdef USE_PCRE2
pcre2_match_data *match_data;
match_data = pcre2_match_data_create_from_pattern(fPriv->fPCRE, nullptr);
#endif

while (kTRUE) {

// find next matching subs
// pcre_exec allows less options - see pcre_internal.h PUBLIC_EXEC_OPTIONS.
#ifdef USE_PCRE2
Int_t nrMatch = pcre2_match(fPriv->fPCRE, (PCRE2_SPTR)s.Data(),
s.Length(), offset, 0,
match_data, nullptr);
#else
Int_t nrMatch = pcre_exec(fPriv->fPCRE, fPriv->fPCREExtra, s.Data(),
s.Length(), offset, 0,
offVec, 3*nMaxMatch);
#endif

if (nrMatch == PCRE_ERROR_NOMATCH) {
break;
Expand All @@ -419,6 +501,12 @@ Int_t TPRegexp::SubstituteInternal(TString &s, const TString &replacePattern,
break;
}

#ifdef USE_PCRE2
PCRE2_SIZE *oVec = pcre2_get_ovector_pointer(match_data);
for (int i = 0; i < 2 * nrMatch; ++i)
offVec[i] = oVec[i];
#endif

// append anything previously unmatched, but not substituted
if (last <= offVec[0]) {
fin += s(last,offVec[0]-last);
Expand Down Expand Up @@ -446,6 +534,9 @@ Int_t TPRegexp::SubstituteInternal(TString &s, const TString &replacePattern,
}
}

#ifdef USE_PCRE2
pcre2_match_data_free(match_data);
#endif
delete [] offVec;

fin += s(last,s.Length()-last);
Expand Down
Loading
Loading