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);
+  }
+}

Reply via email to