diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index c7a008636..d2c1b42d2 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -27,6 +27,7 @@ jobs: libmaxminddb-dev \ libmbedtls-dev \ libmysqlclient-dev \ + libpcre2-dev \ libpcre3-dev \ libpq-dev \ libre2-dev \ @@ -42,7 +43,7 @@ jobs: - name: Run configure run: | - ./configure --enable-extras "argon2 geo_maxmind ldap mysql pgsql regex_pcre regex_posix regex_re2 sqlite3 ssl_gnutls ssl_mbedtls ssl_openssl sslrehashsignal" + ./configure --enable-extras "argon2 geo_maxmind ldap mysql pgsql regex_pcre regex_pcre2 regex_posix regex_re2 sqlite3 ssl_gnutls ssl_mbedtls ssl_openssl sslrehashsignal" ./configure --development --disable-auto-extras --socketengine ${{ matrix.socketengine }} - name: Build core diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 8061c1a0e..1b4e5aecb 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -17,7 +17,7 @@ jobs: - name: Install dependencies run: | brew update || true - for PACKAGE in pkg-config argon2 gnutls libmaxminddb libpq mbedtls mysql-client openssl@1.1 pcre re2 sqlite; + for PACKAGE in pkg-config argon2 gnutls libmaxminddb libpq mbedtls mysql-client openssl@1.1 pcre pcre2 re2 sqlite; do brew install $PACKAGE || brew upgrade $PACKAGE done @@ -26,7 +26,7 @@ jobs: - name: Run configure run: | - ./configure --enable-extras "argon2 geo_maxmind ldap mysql pgsql regex_pcre regex_posix regex_re2 sqlite3 ssl_gnutls ssl_mbedtls ssl_openssl sslrehashsignal" + ./configure --enable-extras "argon2 geo_maxmind ldap mysql pgsql regex_pcre regex_pcre2 regex_posix regex_re2 sqlite3 ssl_gnutls ssl_mbedtls ssl_openssl sslrehashsignal" ./configure --development --disable-auto-extras --socketengine ${{ matrix.socketengine }} - name: Build core diff --git a/.gitignore b/.gitignore index 9c64d0a8c..e41448cd8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ /src/modules/m_mysql.cpp /src/modules/m_pgsql.cpp /src/modules/m_regex_pcre.cpp +/src/modules/m_regex_pcre2.cpp /src/modules/m_regex_posix.cpp /src/modules/m_regex_re2.cpp /src/modules/m_sqlite3.cpp diff --git a/configure b/configure index 3dc22ed5e..4e5263927 100755 --- a/configure +++ b/configure @@ -394,6 +394,7 @@ if (prompt_bool $interactive, $question, 0) { 'm_pgsql.cpp' => 'pg_config --version', 'm_ldap.cpp' => "echo '#include ' | $config{CXX} -E -", 'm_regex_pcre.cpp' => 'pcre-config --version', + 'm_regex_pcre2.cpp' => 'pkg-config --exists libpcre2-8', 'm_regex_posix.cpp' => undef, 'm_regex_re2.cpp' => 'pkg-config --exists re2', 'm_sqlite3.cpp' => 'pkg-config --exists sqlite3', diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example index 423a44891..076590d90 100644 --- a/docs/conf/modules.conf.example +++ b/docs/conf/modules.conf.example @@ -1759,6 +1759,13 @@ # R-line modules. # +#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# +# Regular expression provider for PCRE2 (Perl-Compatible Regular +# Expressions). You need libpcre2 installed to compile and load this +# module. You must have at least 1 provider loaded to use the filter or +# R-line modules. +# + #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-# # Regular Expression Provider for RE2 Regular Expressions. # You need libre2 installed and in your include/library paths in order diff --git a/include/modules/regex.h b/include/modules/regex.h index e4915cbe2..18180d2b8 100644 --- a/include/modules/regex.h +++ b/include/modules/regex.h @@ -139,7 +139,7 @@ class Regex::Exception final * @param error The error which occurred whilst compiling the regular expression. * @param offset The offset at which the errror occurred. */ - Exception(const std::string& regex, const std::string& error, int offset) + Exception(const std::string& regex, const std::string& error, size_t offset) : ModuleException("Error in regex '" + regex + "' at offset " + ConvToStr(offset) + ": " + error) { } diff --git a/src/modules/extra/m_regex_pcre2.cpp b/src/modules/extra/m_regex_pcre2.cpp new file mode 100644 index 000000000..a8e9c535a --- /dev/null +++ b/src/modules/extra/m_regex_pcre2.cpp @@ -0,0 +1,92 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2021 Sadie Powell + * + * This file is part of InspIRCd. InspIRCd is free software: you can + * redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/// $CompilerFlags: find_compiler_flags("libpcre2-8") +/// $LinkerFlags: find_linker_flags("libpcre2-8") + +/// $PackageInfo: require_system("arch") pcre2 +/// $PackageInfo: require_system("centos") pcre2-devel +/// $PackageInfo: require_system("darwin") pcre2 +/// $PackageInfo: require_system("debian") libpcre2-dev +/// $PackageInfo: require_system("ubuntu") libpcre2-dev + + +#include "inspircd.h" +#include "modules/regex.h" + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +#ifdef _WIN32 +# pragma comment(lib, "pcre2-8.lib") +#endif + +class PCRE2Pattern final + : public Regex::Pattern +{ + private: + pcre2_code* regex; + + public: + PCRE2Pattern(const std::string& pattern, uint8_t options) + : Regex::Pattern(pattern, options) + { + int flags = 0; + if (options & Regex::OPT_CASE_INSENSITIVE) + flags &= PCRE2_CASELESS; + + int errorcode; + PCRE2_SIZE erroroffset; + regex = pcre2_compile(reinterpret_cast(pattern.c_str()), pattern.length(), flags, &errorcode, &erroroffset, nullptr); + if (!regex) + { + PCRE2_UCHAR errorstr[128]; + pcre2_get_error_message(errorcode, errorstr, sizeof errorstr); + throw Regex::Exception(pattern, reinterpret_cast(errorstr), erroroffset); + } + } + + ~PCRE2Pattern() override + { + pcre2_code_free(regex); + } + + bool IsMatch(const std::string& text) override + { + pcre2_match_data* unused = pcre2_match_data_create(1, nullptr); + int result = pcre2_match(regex, reinterpret_cast(text.c_str()), text.length(), 0, 0, unused, nullptr); + pcre2_match_data_free(unused); + return result >= 0; + } +}; + +class ModuleRegexPCRE2 final + : public Module +{ + private: + Regex::SimpleEngine regex; + + public: + ModuleRegexPCRE2() + : Module(VF_VENDOR, "Provides the pcre2 regular expression engine which uses the PCRE2 library.") + , regex(this, "pcre2") + { + } +}; + +MODULE_INIT(ModuleRegexPCRE2) diff --git a/win/conanfile.txt b/win/conanfile.txt index 61a25f345..f2ad905da 100644 --- a/win/conanfile.txt +++ b/win/conanfile.txt @@ -12,6 +12,7 @@ libpq/13.2 mysql-connector-c/6.1.11 # openssl/1.1.1k pcre/8.44 +pcre2/10.37 re2/20210401 sqlite3/3.35.5 @@ -23,6 +24,7 @@ libpq:shared=True mysql-connector:shared=True # openssl:shared=True pcre:shared=True +pcre2:shared=True re2:shared=True sqlite3:shared=True diff --git a/win/modules/CMakeLists.txt b/win/modules/CMakeLists.txt index 5c0d80660..335c71159 100644 --- a/win/modules/CMakeLists.txt +++ b/win/modules/CMakeLists.txt @@ -3,6 +3,7 @@ if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake") file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_pgsql.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/") file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_mysql.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/") file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_regex_pcre.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/") + file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_regex_pcre2.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/") file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_regex_re2.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/") file(COPY "${INSPIRCD_BASE}/src/modules/extra/m_sqlite3.cpp" DESTINATION "${INSPIRCD_BASE}/src/modules/")