# HG changeset patch # User Rafael Laboissiere # Date 1668069042 10800 # Thu Nov 10 05:30:42 2022 -0300 # Node ID d3a40a8b730293105a3714c3c24d2d6d873b870a # Parent 0c48b7e6f3cf7ae9af5d6649be608c9a5463455a Switch from PCRE to PCRE2 (bug #61542). * m4/acinclude.m4 (OCTAVE_CHECK_LIB_PCRE_OK): Adjust for PCRE2. * configure.ac: Check for libpcre2-8 instead of libpcre and pcre2.h instead of pcre.h via OCTAVE_CHECK_LIB. * liboctave/util/lo-regexp.h (regexp): Change the name of variable m_data to m_code, for increased coherence. * liboctave/util/lo-regexp.cc: Port code to PCRE2. All functionalities present in the previous version are preserved. Define macro PCRE2_CODE_UNIT_WIDTH. * libinterp/corefcn/regexp.cc: Drop inclusion of pcre.h. * etc/NEWS.8.md: Add note about this change to NEWS file. diff -r 0c48b7e6f3cf -r d3a40a8b7302 configure.ac --- a/configure.ac Fri Nov 11 17:12:41 2022 +0100 +++ b/configure.ac Thu Nov 10 05:30:42 2022 -0300 @@ -1375,14 +1375,17 @@ [Define to 1 to build experimental Virtual Machine evaluator.]) fi -### Check for PCRE regex library. - +### Check for PCRE2 regex library. + +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="-DPCRE2_CODE_UNIT_WIDTH=8 $CPPFLAGS" OCTAVE_CHECK_LIB(pcre, PCRE, - [], [pcre.h pcre/pcre.h], [pcre_compile], [], [], + [], [pcre2.h pcre2/pcre2.h], [pcre2_compile_8], [], [], [OCTAVE_CHECK_LIB_PCRE_OK([], [AC_MSG_ERROR([PCRE library must be built with UTF support (--enable-utf)])]) ], - [libpcre], [REQUIRED]) + [libpcre2-8], [REQUIRED]) +CPPFLAGS="$save_CPPFLAGS" ### Check for Qhull library. diff -r 0c48b7e6f3cf -r d3a40a8b7302 etc/NEWS.8.md --- a/etc/NEWS.8.md Fri Nov 11 17:12:41 2022 +0100 +++ b/etc/NEWS.8.md Thu Nov 10 05:30:42 2022 -0300 @@ -36,6 +36,8 @@ - `Refine` option is now implemented in functions `ode45`, `ode23`, and `ode23s`. +- Octave now requires PCRE2 (UTF-8) instead of PCRE. + ### Graphical User Interface diff -r 0c48b7e6f3cf -r d3a40a8b7302 libinterp/corefcn/regexp.cc --- a/libinterp/corefcn/regexp.cc Fri Nov 11 17:12:41 2022 +0100 +++ b/libinterp/corefcn/regexp.cc Thu Nov 10 05:30:42 2022 -0300 @@ -30,8 +30,6 @@ #include #include -#include - #include "base-list.h" #include "oct-locbuf.h" #include "quit.h" diff -r 0c48b7e6f3cf -r d3a40a8b7302 liboctave/util/lo-regexp.cc --- a/liboctave/util/lo-regexp.cc Fri Nov 11 17:12:41 2022 +0100 +++ b/liboctave/util/lo-regexp.cc Thu Nov 10 05:30:42 2022 -0300 @@ -32,10 +32,11 @@ #include #include -#if defined (HAVE_PCRE_H) -# include -#elif defined (HAVE_PCRE_PCRE_H) -# include +#define PCRE2_CODE_UNIT_WIDTH 8 +#if defined (HAVE_PCRE2_H) +# include +#elif defined (HAVE_PCRE2_PCRE2_H) +# include #endif #include "Matrix.h" @@ -46,6 +47,7 @@ #include "lo-regexp.h" #include "str-vec.h" #include "unistr-wrappers.h" +#include "unwind-prot.h" namespace octave { @@ -64,8 +66,8 @@ void regexp::free (void) { - if (m_data) - pcre_free (static_cast (m_data)); + if (m_code) + pcre2_code_free (static_cast (m_code)); } void @@ -229,22 +231,28 @@ while ((pos = buf_str.find ('\0')) != std::string::npos) buf_str.replace (pos, 1, "\\000"); - const char *err; - int erroffset; + PCRE2_SIZE erroffset; + int errnumber; int pcre_options - = ( (m_options.case_insensitive () ? PCRE_CASELESS : 0) - | (m_options.dotexceptnewline () ? 0 : PCRE_DOTALL) - | (m_options.lineanchors () ? PCRE_MULTILINE : 0) - | (m_options.freespacing () ? PCRE_EXTENDED : 0) - | PCRE_UTF8); + = ( (m_options.case_insensitive () ? PCRE2_CASELESS : 0) + | (m_options.dotexceptnewline () ? 0 : PCRE2_DOTALL) + | (m_options.lineanchors () ? PCRE2_MULTILINE : 0) + | (m_options.freespacing () ? PCRE2_EXTENDED : 0) + | PCRE2_UTF); - m_data = pcre_compile (buf_str.c_str (), pcre_options, - &err, &erroffset, nullptr); + m_code = pcre2_compile (reinterpret_cast (buf_str.c_str ()), + PCRE2_ZERO_TERMINATED, pcre_options, + &errnumber, &erroffset, nullptr); - if (! m_data) - (*current_liboctave_error_handler) - ("%s: %s at position %d of expression", m_who.c_str (), err, erroffset); + if (! m_code) + { + PCRE2_UCHAR err [256]; + pcre2_get_error_message (errnumber, err, sizeof (err)); + (*current_liboctave_error_handler) + ("%s: %s at position %zu of expression", m_who.c_str (), err, + erroffset); + } } regexp::match_data @@ -266,14 +274,13 @@ char *nametable; std::size_t idx = 0; - pcre *re = static_cast (m_data); + pcre2_code *re = static_cast (m_code); - pcre_fullinfo (re, nullptr, PCRE_INFO_CAPTURECOUNT, &subpatterns); - pcre_fullinfo (re, nullptr, PCRE_INFO_NAMECOUNT, &namecount); - pcre_fullinfo (re, nullptr, PCRE_INFO_NAMEENTRYSIZE, &nameentrysize); - pcre_fullinfo (re, nullptr, PCRE_INFO_NAMETABLE, &nametable); + pcre2_pattern_info (re, PCRE2_INFO_CAPTURECOUNT, &subpatterns); + pcre2_pattern_info (re, PCRE2_INFO_NAMECOUNT, &namecount); + pcre2_pattern_info (re, PCRE2_INFO_NAMEENTRYSIZE, &nameentrysize); + pcre2_pattern_info (re, PCRE2_INFO_NAMETABLE, &nametable); - OCTAVE_LOCAL_BUFFER (int, ovector, (subpatterns+1)*3); OCTAVE_LOCAL_BUFFER (int, nidx, namecount); for (int i = 0; i < namecount; i++) @@ -288,49 +295,27 @@ { octave_quit (); - int matches = pcre_exec (re, nullptr, buffer.c_str (), - buffer.length (), idx, - PCRE_NO_UTF8_CHECK | (idx ? PCRE_NOTBOL : 0), - ovector, (subpatterns+1)*3); + PCRE2_SIZE *ovector; + pcre2_match_data *m_data = pcre2_match_data_create_from_pattern (re, NULL); - if (matches == PCRE_ERROR_MATCHLIMIT) - { - // Try harder; start with default value for MATCH_LIMIT - // and increase it. - (*current_liboctave_warning_with_id_handler) - ("Octave:regexp-match-limit", - "your pattern caused PCRE to hit its MATCH_LIMIT; trying harder now, but this will be slow"); + unwind_action cleanup_match_data + ([=] () { pcre2_match_data_free (m_data); }); - pcre_extra pe; - - pcre_config (PCRE_CONFIG_MATCH_LIMIT, - static_cast (&pe.match_limit)); - - pe.flags = PCRE_EXTRA_MATCH_LIMIT; + int matches = pcre2_match (re, reinterpret_cast (buffer.c_str ()), + buffer.length (), idx, + PCRE2_NO_UTF_CHECK | (idx ? PCRE2_NOTBOL : 0), + m_data, nullptr); - int i = 0; - while (matches == PCRE_ERROR_MATCHLIMIT - && i++ < PCRE_MATCHLIMIT_MAX) - { - octave_quit (); + if (matches < 0 && matches != PCRE2_ERROR_NOMATCH) + (*current_liboctave_error_handler) + ("%s: internal error calling pcre2_match; " + "error code from pcre2_match is %i", m_who.c_str (), matches); - pe.match_limit *= 10; - matches = pcre_exec (re, &pe, buffer.c_str (), - buffer.length (), idx, - PCRE_NO_UTF8_CHECK - | (idx ? PCRE_NOTBOL : 0), - ovector, (subpatterns+1)*3); - } - } + if (matches == PCRE2_ERROR_NOMATCH) + break; - if (matches < 0 && matches != PCRE_ERROR_NOMATCH) - (*current_liboctave_error_handler) - ("%s: internal error calling pcre_exec; " - "error code from pcre_exec is %i", m_who.c_str (), matches); - - if (matches == PCRE_ERROR_NOMATCH) - break; - else if (ovector[0] >= ovector[1] && ! m_options.emptymatch ()) + ovector = pcre2_get_ovector_pointer (m_data); + if (ovector[0] >= ovector[1] && ! m_options.emptymatch ()) { // Zero length match. Skip to next char. idx = ovector[0] + 1; @@ -346,7 +331,7 @@ for (int i = 1; i < matches; i++) { - if (ovector[2*i] >= 0 && ovector[2*i+1] > 0 + if (ovector[2*i] != PCRE2_SIZE_MAX && ovector[2*i+1] > 0 && (i == 1 || ovector[2*i] != ovector[2*i-2] || ovector[2*i-1] != ovector[2*i+1])) { @@ -357,20 +342,12 @@ token_extents.resize (pos_match, 2); - double start = double (ovector[0]+1); - double end = double (ovector[1]); - - const char **listptr; - int status = pcre_get_substring_list (buffer.c_str (), ovector, - matches, &listptr); - - if (status == PCRE_ERROR_NOMEMORY) - (*current_liboctave_error_handler) - ("%s: cannot allocate memory in pcre_get_substring_list", - m_who.c_str ()); + PCRE2_SIZE start = ovector[0] + 1; + PCRE2_SIZE end = ovector[1]; // Must use explicit length constructor as match can contain '\0'. - std::string match_string = std::string (*listptr, end - start + 1); + std::string match_string = std::string (buffer.c_str() + start - 1, + end - start + 1); string_vector tokens (pos_match); string_vector named_tokens (m_names); @@ -379,7 +356,7 @@ for (int i = 1; i < matches; i++) { - if (ovector[2*i] >= 0 && ovector[2*i+1] > 0) + if (ovector[2*i] != PCRE2_SIZE_MAX && ovector[2*i+1] > 0) { if (i == 1 || ovector[2*i] != ovector[2*i-2] || ovector[2*i-1] != ovector[2*i+1]) @@ -396,25 +373,25 @@ { std::size_t len = ovector[2*i+1] - ovector[2*i]; named_tokens(m_named_idx(j)) - = std::string (*(listptr+i-pos_offset), - len); + = std::string (buffer.c_str () + ovector[2*i], + len); break; } } } std::size_t len = ovector[2*i+1] - ovector[2*i]; - tokens(pos_match++) = std::string (*(listptr+i), len); + tokens(pos_match++) = std::string (buffer.c_str() + ovector[2*i], len); } else pos_offset++; } } - pcre_free_substring_list (listptr); - regexp::match_element new_elem (named_tokens, tokens, match_string, - token_extents, start, end); + token_extents, + static_cast (start), + static_cast (end)); lst.push_back (new_elem); if (ovector[1] <= ovector[0]) @@ -430,6 +407,7 @@ if (m_options.once () || idx >= buffer.length ()) break; } + } retval = regexp::match_data (lst, m_named_pats); diff -r 0c48b7e6f3cf -r d3a40a8b7302 liboctave/util/lo-regexp.h --- a/liboctave/util/lo-regexp.h Fri Nov 11 17:12:41 2022 +0100 +++ b/liboctave/util/lo-regexp.h Thu Nov 10 05:30:42 2022 -0300 @@ -51,7 +51,7 @@ regexp (const std::string& pat = "", const regexp::opts& opt = regexp::opts (), const std::string& w = "regexp") - : m_pattern (pat), m_options (opt), m_data (nullptr), m_named_pats (), + : m_pattern (pat), m_options (opt), m_code (nullptr), m_named_pats (), m_names (0), m_named_idx (), m_who (w) { compile_internal (); @@ -225,7 +225,7 @@ opts m_options; // Internal data describing the regular expression. - void *m_data; + void *m_code; string_vector m_named_pats; int m_names; diff -r 0c48b7e6f3cf -r d3a40a8b7302 m4/acinclude.m4 --- a/m4/acinclude.m4 Fri Nov 11 17:12:41 2022 +0100 +++ b/m4/acinclude.m4 Thu Nov 10 05:30:42 2022 -0300 @@ -1505,16 +1505,17 @@ [AC_LANG_PUSH(C++) AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include - #if defined (HAVE_PCRE_H) - # include - #elif defined (HAVE_PCRE_PCRE_H) - # include + #define PCRE2_CODE_UNIT_WIDTH 8 + #if defined (HAVE_PCRE2_H) + # include + #elif defined (HAVE_PCRE2_PCRE2_H) + # include #endif ]], [[ const char *pattern = "test"; - const char *err; - int erroffset; - pcre *data = pcre_compile (pattern, PCRE_UTF8, &err, &erroffset, nullptr); + int err; + PCRE2_SIZE erroffset; + pcre2_code *data = pcre2_compile ((PCRE2_SPTR) pattern, PCRE2_ZERO_TERMINATED, PCRE2_UTF, &err, &erroffset, nullptr); return (! data); ]])], octave_cv_lib_pcre_ok=yes,