This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 864e49c683 Expose PCRE2 error codes in tsutils Regex.h API (#12606)
864e49c683 is described below
commit 864e49c68382b7fd618a4cab4b11db0eecb4e00a
Author: Brian Neradt <[email protected]>
AuthorDate: Thu Oct 23 13:31:26 2025 -0500
Expose PCRE2 error codes in tsutils Regex.h API (#12606)
Add REErrors enum to Regex.h to encapsulate PCRE2 error codes, allowing
users to check for specific error conditions without needing to include
pcre2.h directly. For now, the enum includes RE_ERROR_NOMATCH (-1) for
when no match is found and RE_ERROR_NULL (-51) for when NULL code or
subject is passed.
---
include/tsutil/Regex.h | 16 ++++++++++++----
src/tsutil/Regex.cc | 3 +++
src/tsutil/unit_tests/test_Regex.cc | 35 ++++++++++++++++++++++++++++++++---
3 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/include/tsutil/Regex.h b/include/tsutil/Regex.h
index 9ca0608f76..e7dfeb944f 100644
--- a/include/tsutil/Regex.h
+++ b/include/tsutil/Regex.h
@@ -33,10 +33,18 @@
/// @internal These values are copied from pcre2.h, to avoid having to include
it. The values are checked (with
/// static_assert) in Regex.cc against PCRE2 named constants, in case they
change in future PCRE2 releases.
enum REFlags {
- RE_CASE_INSENSITIVE = 0x00000008u, ///< Ignore case (default: case
sensitive).
- RE_UNANCHORED = 0x00000400u, ///< Unanchored (DFA defaults to
anchored).
- RE_ANCHORED = 0x80000000u, ///< Anchored (Regex defaults to
unanchored).
- RE_NOTEMPTY = 0x00000004u ///< Not empty (default: may match empty
string).
+ RE_CASE_INSENSITIVE = 0x00000008u, ///< Ignore case (by default, matches are
case sensitive).
+ RE_UNANCHORED = 0x00000400u, ///< Unanchored (@a DFA defaults to
anchored).
+ RE_ANCHORED = 0x80000000u, ///< Anchored (@a Regex defaults to
unanchored).
+ RE_NOTEMPTY = 0x00000004u ///< Not empty (by default, matches may
match empty string).
+};
+
+/// @brief Error codes returned by regular expression operations.
+///
+/// @internal As with REFlags, these values are copied from pcre2.h, to avoid
having to include it.
+enum REErrors {
+ RE_ERROR_NOMATCH = -1, ///< No match found.
+ RE_ERROR_NULL = -51 ///< NULL code or subject was passed.
};
/// @brief Wrapper for PCRE2 match data.
diff --git a/src/tsutil/Regex.cc b/src/tsutil/Regex.cc
index 32604fb6ae..5535eac537 100644
--- a/src/tsutil/Regex.cc
+++ b/src/tsutil/Regex.cc
@@ -36,6 +36,9 @@ static_assert(RE_UNANCHORED == PCRE2_MULTILINE, "Update
RE_UNANCHORED for curren
static_assert(RE_ANCHORED == PCRE2_ANCHORED, "Update RE_ANCHORED for current
PCRE2 version.");
static_assert(RE_NOTEMPTY == PCRE2_NOTEMPTY, "Update RE_NOTEMPTY for current
PCRE2 version.");
+static_assert(RE_ERROR_NOMATCH == PCRE2_ERROR_NOMATCH, "Update
RE_ERROR_NOMATCH for current PCRE2 version.");
+static_assert(RE_ERROR_NULL == PCRE2_ERROR_NULL, "Update RE_ERROR_NULL for
current PCRE2 version.");
+
//----------------------------------------------------------------------------
namespace
{
diff --git a/src/tsutil/unit_tests/test_Regex.cc
b/src/tsutil/unit_tests/test_Regex.cc
index c2021322bf..b7443df9cd 100644
--- a/src/tsutil/unit_tests/test_Regex.cc
+++ b/src/tsutil/unit_tests/test_Regex.cc
@@ -171,7 +171,7 @@ TEST_CASE("Regex", "[libts][Regex]")
Regex r;
RegexMatches matches;
REQUIRE(r.exec("foo") == false);
- REQUIRE(r.exec("foo", matches) == PCRE2_ERROR_NULL);
+ REQUIRE(r.exec("foo", matches) == RE_ERROR_NULL);
}
// test for recompiling the regular expression
@@ -217,10 +217,10 @@ TEST_CASE("Regex RE_NOTEMPTY flag behavior",
"[libts][Regex][flags][RE_NOTEMPTY]
// boolean overload with RE_NOTEMPTY should not match
CHECK(r.exec(std::string_view(""), RE_NOTEMPTY) == false);
- // matches overload should return a negative value (PCRE2_ERROR_NOMATCH)
+ // matches overload should return RE_ERROR_NOMATCH
RegexMatches matches;
int rc = r.exec(std::string_view(""), matches, RE_NOTEMPTY);
- CHECK(rc < 0);
+ CHECK(rc == RE_ERROR_NOMATCH);
}
SECTION("non-empty subject unaffected by RE_NOTEMPTY for this pattern")
@@ -230,3 +230,32 @@ TEST_CASE("Regex RE_NOTEMPTY flag behavior",
"[libts][Regex][flags][RE_NOTEMPTY]
CHECK(r.exec(std::string_view("a"), RE_NOTEMPTY) == false);
}
}
+
+TEST_CASE("Regex error codes", "[libts][Regex][errors]")
+{
+ SECTION("RE_ERROR_NULL when regex not compiled")
+ {
+ Regex r;
+ RegexMatches matches;
+
+ // exec on uncompiled regex should return RE_ERROR_NULL
+ CHECK(r.exec("test", matches) == RE_ERROR_NULL);
+ }
+
+ SECTION("RE_ERROR_NOMATCH when pattern does not match")
+ {
+ Regex r;
+ REQUIRE(r.compile(R"(^foo$)") == true);
+
+ RegexMatches matches;
+
+ // Pattern does not match, should return RE_ERROR_NOMATCH
+ CHECK(r.exec("bar", matches) == RE_ERROR_NOMATCH);
+ CHECK(r.exec("foobar", matches) == RE_ERROR_NOMATCH);
+ CHECK(r.exec("", matches) == RE_ERROR_NOMATCH);
+
+ // The following should match and return 1 (which shouldn't be
RE_ERROR_NOMATCH)
+ CHECK(r.exec("foo", matches) != RE_ERROR_NOMATCH);
+ CHECK(r.exec("foo", matches) == 1);
+ }
+}