public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/coccinelle] rawhide: New version 1.3.3 (RHBZ#2519492)
@ 2026-09-04 10:20 Richard W.M. Jones
  0 siblings, 0 replies; only message in thread
From: Richard W.M. Jones @ 2026-09-04 10:20 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/coccinelle
            Branch : rawhide
            Commit : fdc6f37097ce284b477965033e55a5cea97edb89
            Author : Richard W.M. Jones <rjones@redhat.com>
            Date   : 2026-09-04T11:06:28+01:00
            Stats  : +9/-9858 in 12 file(s)
            URL    : https://src.fedoraproject.org/rpms/coccinelle/c/fdc6f37097ce284b477965033e55a5cea97edb89?branch=rawhide

            Log:
            New version 1.3.3 (RHBZ#2519492)

Drop ocaml-pcre2, egrep patches which are now upstream.

---
diff --git a/.gitignore b/.gitignore
index 31ea387..d6abfd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 /coccinelle-*.tgz
 /coccinelle-*.tar.gz
 /coccinelle-1.3.1.tar.bz2
+/coccinelle-1.3.3.tar.bz2

diff --git a/0001-replace-pcre-with-pcre2.patch b/0001-replace-pcre-with-pcre2.patch
deleted file mode 100644
index 886dcf7..0000000
--- a/0001-replace-pcre-with-pcre2.patch
+++ /dev/null
@@ -1,272 +0,0 @@
-From 51f5162da9f773ad4efe4572fa49c4334fd35a11 Mon Sep 17 00:00:00 2001
-From: Olaf Hering <olaf@aepfle.de>
-Date: Wed, 19 Mar 2025 09:14:35 +0100
-Subject: [PATCH 1/9] replace pcre with pcre2
-
-Since pcre is unmaintained, the usage of ocaml-pcre will be replaced
-with ocaml-pcre2. While other regular expession libraries for OCaml
-exists, they are not as feature complete as pcre2 is.
-
-This is the minimal change to use the system ocaml-pcre2. To reduce the
-size of this patch, a separate commit might be required to import
-pcre2-ocaml.git into bundles and use it in the build system.
-
-Signed-off-by: Olaf Hering <olaf@aepfle.de>
-(cherry picked from commit 0af334383425b4de18f1d9a087e38838c75c2c4d)
----
- Makefile               |  4 ++--
- Makefile.config.in     | 18 +++++++++---------
- Makefile.libs          | 18 +++++++++---------
- coccinelle.opam        |  2 +-
- configure.ac           | 16 ++++++++--------
- globals/regexp_pcre.ml |  6 +++---
- setup/fake-subst.sh    |  6 +++---
- 7 files changed, 35 insertions(+), 35 deletions(-)
-
-diff --git a/Makefile b/Makefile
-index 0f6b2313f..6b624e378 100644
---- a/Makefile
-+++ b/Makefile
-@@ -101,7 +101,7 @@ PREFIX_spgen := tools/spgen/source/
- CORE_LIBS := unix str ocamlcommon \
- 	$(STDCOMPATDIR)/stdcompat \
- 	$(patsubst %,bytes,$(BYTESDIR)) \
--	$(patsubst %,pcre,$(filter %/pcre.cma,$(LNKLIBS)))
-+	$(patsubst %,pcre2,$(filter %/pcre2.cma,$(LNKLIBS)))
- 
- ifeq ($(OCAMLATLEAST50),no)
- CORE_LIBS += bigarray
-@@ -214,7 +214,7 @@ MENHIR_LIB := \
- 	$(addsuffix /menhirLib$(LIBSUFFIX),$(filter %/menhirLib,$(MAKELIBS)))
- PARMAP_LIB := $(addsuffix /parmap$(LIBSUFFIX),$(filter %/parmap,$(MAKELIBS)))
- PYML_LIB := $(addsuffix /pyml$(LIBSUFFIX),$(filter %/pyml,$(MAKELIBS)))
--PCRE_LIB := $(addsuffix /pcre$(LIBSUFFIX),$(filter %/pcre,$(MAKELIBS)))
-+PCRE_LIB := $(addsuffix /pcre2$(LIBSUFFIX),$(filter %/pcre2,$(MAKELIBS)))
- STDCOMPAT_LIB := $(STDCOMPATDIR)/stdcompat$(LIBSUFFIX)
- 
- STDCOMPAT_USERS := parsing_c/type_annoter_c cocci parsing_cocci/check_meta \
-diff --git a/Makefile.config.in b/Makefile.config.in
-index dbafa35a5..6bad1a7a6 100644
---- a/Makefile.config.in
-+++ b/Makefile.config.in
-@@ -5,18 +5,18 @@
- VERSION=@PACKAGE_VERSION@
- 
- # * for each library $1, add another entry in the same manner
--MAKELIBS=@MAKE_dynlink@ @MAKE_menhirLib@ @MAKE_pyml@ @MAKE_pcre@ \
-+MAKELIBS=@MAKE_dynlink@ @MAKE_menhirLib@ @MAKE_pyml@ @MAKE_pcre2@ \
-   @MAKE_parmap@
--LNKLIBS=@MODULES_dynlink@ @MODULES_menhirLib@ @MODULES_pcre@ @MODULES_pyml@ \
-+LNKLIBS=@MODULES_dynlink@ @MODULES_menhirLib@ @MODULES_pcre2@ @MODULES_pyml@ \
-   @MODULES_parmap@
- OPTLNKLIBS=@MODULESOPT_dynlink@ @MODULESOPT_menhirLib@ @MODULESOPT_pyml@ \
--  @MODULESOPT_pcre@ @MODULESOPT_parmap@
--INCLIBS=@PATH_dynlink@ @PATH_menhirLib@ @PATH_pyml@ @PATH_pcre@ \
-+  @MODULESOPT_pcre2@ @MODULESOPT_parmap@
-+INCLIBS=@PATH_dynlink@ @PATH_menhirLib@ @PATH_pyml@ @PATH_pcre2@ \
-   @PATH_parmap@
--FLAGSLIBS=@FLAGS_dynlink@ @FLAGS_menhirLib@ @FLAGS_pyml@ @FLAGS_pcre@ \
-+FLAGSLIBS=@FLAGS_dynlink@ @FLAGS_menhirLib@ @FLAGS_pyml@ @FLAGS_pcre2@ \
-   @FLAGS_parmap@
- OPTFLAGSLIBS=@OPTFLAGS_dynlink@ @OPTFLAGS_menhirLib@ @OPTFLAGS_pyml@ \
--  @OPTFLAGS_pcre@ @OPTFLAGS_parmap@
-+  @OPTFLAGS_pcre2@ @OPTFLAGS_parmap@
- # * end of library variables
- 
- # system packages inc libs
-@@ -106,7 +106,7 @@ METAINFO_DIR=@METAINFO_DIR@
- 
- # selected libraries
- FEATURE_menhirLib=@FEATURE_menhirLib@
--FEATURE_pcre=@FEATURE_pcre@
-+FEATURE_pcre=@FEATURE_pcre2@
- 
- # Features
- FEATURE_PYTHON=@FEATURE_PYTHON@
-@@ -114,7 +114,7 @@ FEATURE_OCAML=@FEATURE_OCAML@
- NO_OCAMLFIND=@SUBSTITUTED_OCAMLFIND@
- 
- # Include paths
--PCREDIR=@PATH_pcre@
-+PCREDIR=@PATH_pcre2@
- PARMAPDIR=@PATH_parmap@
- PYMLDIR=@PATH_pyml@
- MENHIRDIR=@PATH_menhirLib@
-@@ -129,4 +129,4 @@ REGEXP_FILE=@REGEXP_FILE@
- 
- MENHIR_FLAGS=@DEFAULT_MENHIR_FLAGS@
- 
--OCAMLATLEAST50=@OCAMLATLEAST50@
-\ No newline at end of file
-+OCAMLATLEAST50=@OCAMLATLEAST50@
-diff --git a/Makefile.libs b/Makefile.libs
-index 96e05d26f..ed6ce302f 100644
---- a/Makefile.libs
-+++ b/Makefile.libs
-@@ -36,15 +36,15 @@ OPTFLAGS_pyml  = $(CFLAGS_pyml:%=-ccopt %) -cclib -lpyml_stubs
- 
- # pcre library
- # Note: see the comment of the pycaml library about the double appearance of the stubs library.
--LOCAL_pcre     = $(BYTESDIR:=/bytes.cma) $(PCREDIR)/pcre.cma
--LOCALOPT_pcre  = $(BYTESDIR:=/bytes.cmxa) $(PCREDIR)/pcre.cmxa
--GLOBAL_pcre    = $(BYTESDIR:=/bytes.cma) $(PCREDIR)/pcre.cma
--GLOBALOPT_pcre = $(BYTESDIR:=/bytes.cmxa) $(PCREDIR)/pcre.cmxa
--FLAGS_pcre     = \
--	$(PCRE_LIBS:%=-ccopt %) -cclib -L$(PCREDIR) -dllib -lpcre_stubs \
--	-cclib -lpcre_stubs
--OPTFLAGS_pcre  = \
--	$(PCRE_LIBS:%=-ccopt %) -cclib -L$(PCREDIR) -cclib -lpcre_stubs
-+LOCAL_pcre2     = $(BYTESDIR:=/bytes.cma) $(PCREDIR)/pcre2.cma
-+LOCALOPT_pcre2  = $(BYTESDIR:=/bytes.cmxa) $(PCREDIR)/pcre2.cmxa
-+GLOBAL_pcre2    = $(BYTESDIR:=/bytes.cma) $(PCREDIR)/pcre2.cma
-+GLOBALOPT_pcre2 = $(BYTESDIR:=/bytes.cmxa) $(PCREDIR)/pcre2.cmxa
-+FLAGS_pcre2     = \
-+	$(PCRE_LIBS:%=-ccopt %) -cclib -L$(PCREDIR) -dllib -lpcre2_stubs \
-+	-cclib -lpcre2_stubs
-+OPTFLAGS_pcre2  = \
-+	$(PCRE_LIBS:%=-ccopt %) -cclib -L$(PCREDIR) -cclib -lpcre2_stubs
- 
- # dynlink library
- LOCAL_dynlink     =
-diff --git a/coccinelle.opam b/coccinelle.opam
-index ce7485c7a..c07ebce0d 100644
---- a/coccinelle.opam
-+++ b/coccinelle.opam
-@@ -18,7 +18,7 @@ depends: [
-   "ocaml"
-   "menhir"
-   "ocamlfind"
--  "pcre"
-+  "pcre2"
-   "stdcompat"
-   "pyml" { >= "20171117" }
-   "conf-pkg-config"
-diff --git a/configure.ac b/configure.ac
-index 9106bc704..cd9005a87 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -144,7 +144,7 @@ dnl  add a line for each package that is
- dnl  configured via AC_CHECK_COCCI_EXTPKG
- dnl  or AC_REQ_COCCI_EXTPKG
- AC_COCCI_INIT_PKG_EMPTY([dynlink])
--AC_COCCI_INIT_PKG_EMPTY([pcre])
-+AC_COCCI_INIT_PKG_EMPTY([pcre2])
- AC_COCCI_INIT_PKG_EMPTY([bytes]) dnl for recent versions of pcre on old OCaml
- AC_COCCI_INIT_PKG_EMPTY([pyml])
- AC_COCCI_INIT_PKG_EMPTY([stdcompat])
-@@ -368,18 +368,18 @@ dnl    OCAML_PKG_pcre: if "local" use str package
- AC_ARG_ENABLE([pcre-syntax], AS_HELP_STRING([--enable-pcre-syntax], [enable pcre regular expression syntax (default: auto)]))
- AS_IF([test "x$enable_pcre_syntax" != "xno"],
- [dnl
--  PKG_CHECK_MODULES([PCRE], [libpcre],[AC_SUBST([HAVE_PCRE],[yes])],[AC_SUBST([HAVE_PCRE],[no])])
-+  PKG_CHECK_MODULES([PCRE], [libpcre2-8],[AC_SUBST([HAVE_PCRE],[yes])],[AC_SUBST([HAVE_PCRE],[no])])
-   AS_IF([test -z "$enable_pcre_syntax" -a "x$HAVE_PCRE" != xyes],
-   [dnl
-     AC_SUBST([enable_pcre_syntax], [no])
-   ],
-   [dnl
-     AS_IF([test "x$enable_pcre" = "xno"], [AC_SUBST([enable_pcre], [local])])
--    AC_CHECK_COCCI_EXTPKG([pcre])  dnl  will set $enable_pcre to 'yes', 'no', or 'local'
-+    AC_CHECK_COCCI_EXTPKG([pcre2])  dnl  will set $enable_pcre to 'yes', 'no', or 'local'
-     AS_IF([test "x$enable_pcre" = "xyes"],
-     [dnl
-       AC_MSG_CHECKING([if pcre depends on bytes])
--      AS_IF([test "x`$OCAMLFIND query -r -format '%p' pcre 2>/dev/null | grep bytes`" = "xbytes"],
-+      AS_IF([test "x`$OCAMLFIND query -r -format '%p' pcre2 2>/dev/null | grep bytes`" = "xbytes"],
-       [dnl
-         AC_MSG_RESULT([yes])
-         AC_MSG_CHECKING([if bytes is an actual module])
-@@ -406,14 +406,14 @@ AS_IF([test "x$enable_pcre_syntax" != xno],
-     AC_MSG_NOTICE([support for pcre syntax is enabled])
-   ],
-   [dnl
--    AC_MSG_ERROR([the pcre feature is enabled but the pkg-config libpcre library is not found])
-+    AC_MSG_ERROR([the pcre feature is enabled but the pkg-config libpcre2-8 library is not found])
-   ])
- 
-   AC_SUBST([REGEXP_MODULE], [Regexp_pcre])
-   AC_SUBST([REGEXP_FILE], [regexp_pcre.ml])
- ],
- [dnl
--  AC_COCCI_INIT_PKG_EMPTY([pcre])
-+  AC_COCCI_INIT_PKG_EMPTY([pcre2])
-   AC_SUBST([REGEXP_MODULE], [Regexp_str])
-   AC_SUBST([REGEXP_FILE], [regexp_str.ml])
- ])
-@@ -570,7 +570,7 @@ AS_IF([test "$MAKE_stdcompat"],
- AS_IF([test "$MAKE_parmap"],
-   AC_CONFIG_SUBDIRS(bundles/parmap))
- 
--AS_IF([test "$MAKE_pcre"],
-+AS_IF([test "$MAKE_pcre2"],
-   [AS_IF([test "x$OCAMLATLEAST4030" = xno  ],
-     [AC_SUBST([CAMLnoreturn_start], [])
-      AC_SUBST([CAMLnoreturn_end], [])],
-@@ -632,7 +632,7 @@ python scripting: $enable_python	(overridable with --enable-python)
- 
- pcre regexes:     $enable_pcre_syntax	(overridable with --enable-pcre-syntax)
- pcre module:      $enable_pcre	(for local package use --disable-pcre)
--pcre library:     $HAVE_PCRE	(requires the libpcre-ocaml-dev package)
-+pcre library:     $HAVE_PCRE	(requires the libpcre2-ocaml-dev package)
- 
- optimized spatch: $enable_opt	(overridable with --disable-opt)
- 
-diff --git a/globals/regexp_pcre.ml b/globals/regexp_pcre.ml
-index d09f8528f..93073758f 100644
---- a/globals/regexp_pcre.ml
-+++ b/globals/regexp_pcre.ml
-@@ -5,7 +5,7 @@
-  *)
- 
- type regexp =
--    Pcre of int (* Pcre.regexp *)
-+    Pcre of int (* Pcre2.regexp *)
-   | Str of Str.regexp
- 
- (* A table is used because PCRE regular expressions are not comparable.
-@@ -26,7 +26,7 @@ let regexp string =
-     begin
-       let c = !pcre_ctr in
-       pcre_ctr := !pcre_ctr + 1;
--      Hashtbl.add pcre_table c (Pcre.regexp string);
-+      Hashtbl.add pcre_table c (Pcre2.regexp string);
-       Pcre c
-     end
-   else Str (Str.regexp string)
-@@ -35,7 +35,7 @@ let string_match regexp string =
-   match regexp with
-       Pcre regexp ->
- 	let regexp = Hashtbl.find pcre_table regexp in
--	Pcre.pmatch ~rex:regexp string
-+	Pcre2.pmatch ~rex:regexp string
-     | Str regexp ->
-       try
- 	ignore(Str.search_forward regexp string 0);
-diff --git a/setup/fake-subst.sh b/setup/fake-subst.sh
-index eb999d3ec..2aa2a2702 100755
---- a/setup/fake-subst.sh
-+++ b/setup/fake-subst.sh
-@@ -19,7 +19,7 @@ set -e
- # the next lines in the file.
- 
- # the replies file assumes that the
--# libpcre and python libraries are installed, and
-+# libpcre2 and python libraries are installed, and
- # that none of the optional ocaml libraries are
- # installed.
- 
-@@ -102,9 +102,9 @@ pythonlibs() {
-   echo "-L${prefix}/lib -lpython${version}"
- }
- 
--# succeeds only if "/usr/include/pcre.h" exists
-+# succeeds only if "/usr/include/pcre2.h" exists
- checkpcre() {
--  test -f /usr/include/pcre.h
-+  test -f /usr/include/pcre2.h
- }
- 
- # iterate through pattern-response pairs
--- 
-2.52.0
-

diff --git a/0002-use-pcre2-instead-of-pcre-in-some-more-places.patch b/0002-use-pcre2-instead-of-pcre-in-some-more-places.patch
deleted file mode 100644
index a40d2db..0000000
--- a/0002-use-pcre2-instead-of-pcre-in-some-more-places.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From 321f6c1317d53c3263a4e0f35d2a43f2ab85f56b Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Wed, 17 Dec 2025 13:28:06 +0100
-Subject: [PATCH 2/9] use pcre2 instead of pcre in some more places
-
-(cherry picked from commit fa062fb3660b1237d32d27fb5027cb68f4c5aae1)
----
- Makefile | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/Makefile b/Makefile
-index 6b624e378..cddb81ce6 100644
---- a/Makefile
-+++ b/Makefile
-@@ -121,7 +121,7 @@ LIBRARIES_spatch := $(LIBRARIES)
- 
- LIBRARIES_spgen := $(CORE_LIBRARIES)
- 
--CORE_BUNDLES=stdcompat menhirLib pcre
-+CORE_BUNDLES=stdcompat menhirLib pcre2
- 
- ALL_BUNDLES=$(CORE_BUNDLES) parmap pyml
- 
-@@ -319,8 +319,8 @@ install-spatch : spatch$(TOOLS_SUFFIX)
- 		$(INSTALL_PROGRAM) bundles/pyml/dllpyml_stubs.so \
- 			$(DESTDIR)$(LIBDIR); \
- 	fi
--	if test -f bundles/pcre/dllpcre_stubs.so; then \
--		$(INSTALL_PROGRAM) bundles/pcre/dllpcre_stubs.so \
-+	if test -f bundles/pcre2/dllpcre2_stubs.so; then \
-+		$(INSTALL_PROGRAM) bundles/pcre2/dllpcre2_stubs.so \
- 			$(DESTDIR)$(LIBDIR); \
- 	fi
- 	$(INSTALL_PROGRAM) spatch$(TOOLS_SUFFIX) $(DESTDIR)$(BINDIR)/spatch
-@@ -521,11 +521,11 @@ endif
- ifneq ($(PCRE_LIB),)
- ifeq ($(NATIVE),yes)
- $(PCRE_LIB): $(STDCOMPAT_LIB)
--	$(MAKE) -C bundles/pcre all
--	$(MAKE) -C bundles/pcre all.opt
-+	$(MAKE) -C bundles/pcre2 all
-+	$(MAKE) -C bundles/pcre2 all.opt
- else
- $(PCRE_LIB): $(STDCOMPAT_LIB)
--	$(MAKE) -C bundles/pcre all
-+	$(MAKE) -C bundles/pcre2 all
- endif
- endif
- 
--- 
-2.52.0
-

diff --git a/0003-replace-pcre-with-pcre2-in-install.txt-instructions.patch b/0003-replace-pcre-with-pcre2-in-install.txt-instructions.patch
deleted file mode 100644
index 78d46c4..0000000
--- a/0003-replace-pcre-with-pcre2-in-install.txt-instructions.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From d35f8b08de850f591408a0f6cdd5de25f1751947 Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Wed, 17 Dec 2025 11:39:12 +0100
-Subject: [PATCH 3/9] replace pcre with pcre2 in install.txt instructions
-
-(cherry picked from commit 0facd403f168aabe21ae19b0f0d9491a36271b4b)
----
- install.txt | 20 ++++++++++----------
- 1 file changed, 10 insertions(+), 10 deletions(-)
-
-diff --git a/install.txt b/install.txt
-index 0ae9a3889..13aee9ae7 100644
---- a/install.txt
-+++ b/install.txt
-@@ -30,14 +30,14 @@ On Debian/Ubuntu, install the following packages:
-     If you do not install libparmap-ocaml-dev, then you will automatically use
-     the bundle instead. However, if you used opam to switch to a different
-     version of OCaml, you must uninstall libparmap-ocaml-dev / libparmap-ocaml.
-- - libpcre-ocaml-dev (optional, for PCRE support, bundled)
--    If you do not install libpcre-ocaml-dev, then you will automatically use
-+ - libpcre2-ocaml-dev (optional, for PCRE support, bundled)
-+    If you do not install libpcre2-ocaml-dev, then you will automatically use
-     the bundle instead. However, in order for the bundle to work, you also
-     need:
--  - libpcre3-dev (optional, not bundled)
-+  - libpcre2-dev (optional, not bundled)
-      Additionally, if you used opam to switch to a different version of OCaml
--     and want PCRE support, then make sure you have libpcre-ocaml-dev /
--     libpcre-ocaml uninstalled and libpcre3-dev installed, otherwise Coccinelle
-+     and want PCRE support, then make sure you have libpcre2-ocaml-dev /
-+     libpcre2-ocaml uninstalled and libpcre2-dev installed, otherwise Coccinelle
-      will not compile.
- 
- On Fedora, install the following packages:
-@@ -49,16 +49,16 @@ On Fedora, install the following packages:
-  - ocaml-findlib-devel
-  - ocaml-ocamldoc
-  - ocaml-menhir (optional, bundled)
-- - ocaml-pcre-devel (optional, bundled)
-+ - ocaml-pcre2-devel (optional, bundled)
-     Note: if you used opam to switch to a different version of OCaml,
--    installing ocaml-pcre-devel will make compilation impossible. Additionally,
-+    installing ocaml-pcre2-devel will make compilation impossible. Additionally,
-     PCRE support and OCaml scripting will be impossible.
- If you want Python scripting: Coccinelle is not compatible with Python 3.13,
- which is the default on Fedora as of 2024-12-19. Consider switching to Python
- 3.12, for example.
- 
- On Arch Linux, install the following packages:
--$ pacman -Syu pkg-config ocaml ocaml-findlib autoconf automake pcre make
-+$ pacman -Syu pkg-config ocaml ocaml-findlib autoconf automake pcre2 make
- as well as the C compiler of your choice.
- Note: if you used opam to switch to a different version of OCaml, OCaml
- scripting will be impossible.
-@@ -70,12 +70,12 @@ bundles):
-   dev-build/libtool
-   dev-lang/ocaml
-   dev-lang/python
--  dev-libs/libpcre
-+  dev-libs/libpcre2
-   dev-ml/camlp4
-   dev-ml/findlib
-   dev-ml/menhir
-   dev-ml/parmap
--  dev-ml/pcre-ocaml
-+  dev-ml/pcre2-ocaml
-   dev-ml/stdcompat
- You may also need:
-   dev-ml/sexplib
--- 
-2.52.0
-

diff --git a/0004-replace-pcre-bundle-with-pcre2-bundle.patch b/0004-replace-pcre-bundle-with-pcre2-bundle.patch
deleted file mode 100644
index c49a587..0000000
--- a/0004-replace-pcre-bundle-with-pcre2-bundle.patch
+++ /dev/null
@@ -1,9235 +0,0 @@
-From bd1adc7faf90939e796ca053b90f7d45da2cbd5c Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Wed, 14 Jan 2026 12:03:48 +0100
-Subject: [PATCH 4/9] replace pcre bundle with pcre2 bundle
-
-Source for pcre2 code:
-https://github.com/camlp5/pcre2-ocaml/tree/4c932fcb4d9d27a077d02369196ab3f0a5774362
-
-(cherry picked from commit d1a67eab7aa4a10e54a15ff515173aae76b3b3d7)
----
- bundles/pcre/.gitignore                       |    4 -
- bundles/pcre/bytes_compat.ml                  |    5 -
- bundles/pcre/pcre-ocaml/CHANGES.md            |   29 -
- bundles/pcre/pcre-ocaml/Makefile              |   10 -
- bundles/pcre/pcre-ocaml/README.md             |  110 --
- bundles/pcre/pcre-ocaml/dune                  |    4 -
- bundles/pcre/pcre-ocaml/dune-project          |    2 -
- bundles/pcre/pcre-ocaml/examples/Makefile     |    9 -
- bundles/pcre/pcre-ocaml/examples/README.md    |   28 -
- bundles/pcre/pcre-ocaml/examples/dune         |    4 -
- bundles/pcre/pcre-ocaml/examples/pcregrep.ml  |  113 --
- bundles/pcre/pcre-ocaml/examples/subst.ml     |   54 -
- bundles/pcre/pcre-ocaml/pcre.opam             |   27 -
- .../pcre/pcre-ocaml/pre-v7.3.0-CHANGES.txt    |  698 ----------
- bundles/pcre/pcre-ocaml/src/.gitignore        |    1 -
- bundles/pcre/pcre-ocaml/src/Makefile          |    9 -
- .../pcre/pcre-ocaml/src/config/discover.ml    |   15 -
- bundles/pcre/pcre-ocaml/src/config/dune       |    4 -
- bundles/pcre/pcre-ocaml/src/dune              |   16 -
- bundles/pcre/pcre-ocaml/src/pcre.ml.in        | 1055 --------------
- bundles/pcre/pcre-ocaml/src/pcre.mli          |  930 -------------
- bundles/pcre/pcre-ocaml/src/pcre_stubs.c.in   |  862 ------------
- .../pcre2-ocaml}/.gitignore                   |    0
- bundles/pcre2/pcre2-ocaml/CHANGELOG.md        |   69 +
- .../pcre2-ocaml}/LICENSE.md                   |    4 +-
- bundles/pcre2/pcre2-ocaml/Makefile            |   15 +
- bundles/pcre2/pcre2-ocaml/README.md           |  138 ++
- bundles/pcre2/pcre2-ocaml/dune                |    9 +
- bundles/pcre2/pcre2-ocaml/dune-project        |   32 +
- bundles/pcre2/pcre2-ocaml/examples/Makefile   |    9 +
- bundles/pcre2/pcre2-ocaml/examples/README.md  |   48 +
- .../pcre2-ocaml}/examples/cloc.ml             |    2 +-
- .../pcre2-ocaml}/examples/count_hash.ml       |    6 +-
- .../pcre2/pcre2-ocaml/examples/dfa_restart.ml |   40 +
- bundles/pcre2/pcre2-ocaml/examples/dune       |    4 +
- .../pcre2/pcre2-ocaml/examples/pcre2grep.ml   |  128 ++
- bundles/pcre2/pcre2-ocaml/examples/subst.ml   |   57 +
- bundles/pcre2/pcre2-ocaml/lib/Makefile        |   15 +
- .../pcre2-ocaml/lib}/config/Makefile          |    0
- .../pcre2/pcre2-ocaml/lib/config/discover.ml  |   14 +
- bundles/pcre2/pcre2-ocaml/lib/config/dune     |    4 +
- bundles/pcre2/pcre2-ocaml/lib/dune            |   18 +
- bundles/pcre2/pcre2-ocaml/lib/pcre2.ml        | 1231 +++++++++++++++++
- bundles/pcre2/pcre2-ocaml/lib/pcre2.mli       | 1068 ++++++++++++++
- bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c   |  807 +++++++++++
- .../pcre2/pcre2-ocaml/pa_ppx_test/Makefile    |   11 +
- .../pcre2-ocaml/pa_ppx_test/pcre2_tests.ml    |  249 ++++
- bundles/pcre2/pcre2-ocaml/pcre2.opam          |   37 +
- bundles/pcre2/pcre2-ocaml/test/dune           |   14 +
- .../pcre2/pcre2-ocaml/test/old_pcre2_tests.ml |   24 +
- bundles/pcre2/pcre2-ocaml/test/pcre2_tests.ml |  746 ++++++++++
- 51 files changed, 4794 insertions(+), 3994 deletions(-)
- delete mode 100644 bundles/pcre/.gitignore
- delete mode 100644 bundles/pcre/bytes_compat.ml
- delete mode 100644 bundles/pcre/pcre-ocaml/CHANGES.md
- delete mode 100644 bundles/pcre/pcre-ocaml/Makefile
- delete mode 100644 bundles/pcre/pcre-ocaml/README.md
- delete mode 100644 bundles/pcre/pcre-ocaml/dune
- delete mode 100644 bundles/pcre/pcre-ocaml/dune-project
- delete mode 100644 bundles/pcre/pcre-ocaml/examples/Makefile
- delete mode 100644 bundles/pcre/pcre-ocaml/examples/README.md
- delete mode 100644 bundles/pcre/pcre-ocaml/examples/dune
- delete mode 100644 bundles/pcre/pcre-ocaml/examples/pcregrep.ml
- delete mode 100644 bundles/pcre/pcre-ocaml/examples/subst.ml
- delete mode 100644 bundles/pcre/pcre-ocaml/pcre.opam
- delete mode 100644 bundles/pcre/pcre-ocaml/pre-v7.3.0-CHANGES.txt
- delete mode 100644 bundles/pcre/pcre-ocaml/src/.gitignore
- delete mode 100644 bundles/pcre/pcre-ocaml/src/Makefile
- delete mode 100644 bundles/pcre/pcre-ocaml/src/config/discover.ml
- delete mode 100644 bundles/pcre/pcre-ocaml/src/config/dune
- delete mode 100644 bundles/pcre/pcre-ocaml/src/dune
- delete mode 100644 bundles/pcre/pcre-ocaml/src/pcre.ml.in
- delete mode 100644 bundles/pcre/pcre-ocaml/src/pcre.mli
- delete mode 100644 bundles/pcre/pcre-ocaml/src/pcre_stubs.c.in
- rename bundles/{pcre/pcre-ocaml => pcre2/pcre2-ocaml}/.gitignore (100%)
- create mode 100644 bundles/pcre2/pcre2-ocaml/CHANGELOG.md
- rename bundles/{pcre/pcre-ocaml => pcre2/pcre2-ocaml}/LICENSE.md (99%)
- create mode 100644 bundles/pcre2/pcre2-ocaml/Makefile
- create mode 100644 bundles/pcre2/pcre2-ocaml/README.md
- create mode 100644 bundles/pcre2/pcre2-ocaml/dune
- create mode 100644 bundles/pcre2/pcre2-ocaml/dune-project
- create mode 100644 bundles/pcre2/pcre2-ocaml/examples/Makefile
- create mode 100644 bundles/pcre2/pcre2-ocaml/examples/README.md
- rename bundles/{pcre/pcre-ocaml => pcre2/pcre2-ocaml}/examples/cloc.ml (97%)
- rename bundles/{pcre/pcre-ocaml => pcre2/pcre2-ocaml}/examples/count_hash.ml (62%)
- create mode 100644 bundles/pcre2/pcre2-ocaml/examples/dfa_restart.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/examples/dune
- create mode 100644 bundles/pcre2/pcre2-ocaml/examples/pcre2grep.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/examples/subst.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/Makefile
- rename bundles/{pcre/pcre-ocaml/src => pcre2/pcre2-ocaml/lib}/config/Makefile (100%)
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/config/discover.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/config/dune
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/dune
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/pcre2.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/pcre2.mli
- create mode 100644 bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c
- create mode 100644 bundles/pcre2/pcre2-ocaml/pa_ppx_test/Makefile
- create mode 100644 bundles/pcre2/pcre2-ocaml/pa_ppx_test/pcre2_tests.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/pcre2.opam
- create mode 100644 bundles/pcre2/pcre2-ocaml/test/dune
- create mode 100644 bundles/pcre2/pcre2-ocaml/test/old_pcre2_tests.ml
- create mode 100644 bundles/pcre2/pcre2-ocaml/test/pcre2_tests.ml
-
-diff --git a/bundles/pcre/.gitignore b/bundles/pcre/.gitignore
-deleted file mode 100644
-index 2388919a1..000000000
---- a/bundles/pcre/.gitignore
-+++ /dev/null
-@@ -1,4 +0,0 @@
--META
--mmottl-pcre-ocaml-258b72c
--.prepare
--pcre-ocaml/src/pcre.ml
-\ No newline at end of file
-diff --git a/bundles/pcre/bytes_compat.ml b/bundles/pcre/bytes_compat.ml
-deleted file mode 100644
-index fd7c2c8b9..000000000
---- a/bundles/pcre/bytes_compat.ml
-+++ /dev/null
-@@ -1,5 +0,0 @@
--include String
--
--external unsafe_to_string: t -> string = "%identity"
--
--external unsafe_of_string: string -> t = "%identity"
-diff --git a/bundles/pcre/pcre-ocaml/CHANGES.md b/bundles/pcre/pcre-ocaml/CHANGES.md
-deleted file mode 100644
-index 0b0f5ba92..000000000
---- a/bundles/pcre/pcre-ocaml/CHANGES.md
-+++ /dev/null
-@@ -1,29 +0,0 @@
--### 7.3.5 (2018-10-25)
--
--  * Switched to dune, dune-release, and OPAM 2.0
--
--
--### 7.3.4 (2017-11-22)
--
--  * Improved finalization of regular expressions and tables for better
--    performance
--
--
--### 7.3.3 (2017-10-17)
--
--  * Fixed external declaration bug in internal regexp compile function
--
--
--### 7.3.2 (2017-10-10)
--
--  * Improved compatibility with MSVC
--
--
--### 7.3.1 (2017-10-08)
--
--  * Used untagged integers when declaring external functions
--
--
--### 7.3.0 (2017-07-27)
--
--  * Switched to jbuilder and topkg
-diff --git a/bundles/pcre/pcre-ocaml/Makefile b/bundles/pcre/pcre-ocaml/Makefile
-deleted file mode 100644
-index 8a5fb073c..000000000
---- a/bundles/pcre/pcre-ocaml/Makefile
-+++ /dev/null
-@@ -1,10 +0,0 @@
--.PHONY: all clean doc
--
--all:
--	dune build @install
--
--clean:
--	dune clean
--
--doc:
--	dune build @doc
-diff --git a/bundles/pcre/pcre-ocaml/README.md b/bundles/pcre/pcre-ocaml/README.md
-deleted file mode 100644
-index b11e04116..000000000
---- a/bundles/pcre/pcre-ocaml/README.md
-+++ /dev/null
-@@ -1,110 +0,0 @@
--## PCRE-OCaml - Perl Compatibility Regular Expressions for OCaml
--
--This [OCaml](http://www.ocaml.org)-library interfaces the C-library
--[PCRE](http://www.pcre.org) (Perl-compatibility Regular Expressions).  It can be
--used for string matching with "PERL"-style regular expressions.
--
--### Features
--
--PCRE-OCaml offers the following functionality for operating on strings:
--
--  * Searching for patterns
--  * Extracting subpatterns
--  * Splitting strings according to patterns
--  * Pattern substitution
--
--Other reasons to use PCRE-OCaml:
--
--  * The PCRE-library by Philip Hazel has been under development for many
--    years and is fairly advanced and stable.  It implements just about all
--    of the functionality that can be found in PERL regular expressions.
--    The higher-level functions written in OCaml (split, replace, etc.),
--    too, are compatible with the corresponding PERL-functions to the extent
--    that OCaml allows.  Most people find the syntax of PERL-style regular
--    expressions more straightforward and powerful than the Emacs-style regular
--    expressions used in the `Str`-module in the standard OCaml distribution.
--
--  * PCRE-OCaml is reentrant and thus thread-safe, which is not the case
--    for the `Str`-module in the OCaml standard library.  Using reentrant
--    libraries also means more convenience for programmers.  They do not
--    have to reason about states in which the library might be in.
--
--  * The high-level functions for replacement and substitution, which are all
--    implemented in OCaml, are much faster than the ones in the `Str`-module.
--    In fact, when compiled to native code, they even seem to be significantly
--    faster than those found in PERL (PERL is written in C).
--
--  * You can rely on the data returned being unique.  In other terms: if
--    the result of a function is a string, you can safely use destructive
--    updates on it without having to fear side effects.
--
--  * The interface to the library makes use of labels and default arguments
--    to give you a high degree of programming comfort.
--
--### Usage
--
--Please consult the [API](https://mmottl.github.io/pcre-ocaml/api/pcre)
--for details.
--
--A general concept the user may need to understand is that most functions
--allow for two different kinds of flags:
--
--  1. "Convenience"-flags that make for readable and concise code, but which
--     need to be translated to an internal representation on each call.
--     Example:
--
--     ```ocaml
--     let rex = Pcre.regexp ~flags:[`ANCHORED; `CASELESS] "some pattern" in
--     (* ... *)
--     ```
--
--     This makes it easy to pass flags on the fly.  They will be translated to
--     the internal format automatically.  However, if this happens to be in a
--     loop, this translation will occur on each iteration.  If you really need
--     to save as much performance as possible, you should use the next approach.
--
--  2. "Internal" flags that need to be defined and translated from
--     "convenience"-flags before function calls, but which allow for optimum
--     performance in loops.  Example:
--
--     ```ocaml
--     let iflags = Pcre.cflags [`ANCHORED; `CASELESS] in
--     for i = 1 to 1000 do
--       let rex = Pcre.regexp ~iflags "some pattern constructed at runtime" in
--       (* ... *)
--     done
--     ```
--
--      Factoring out the translation of flags for regular expressions may
--      save some cycles, but don't expect too much.  You can save more CPU
--      time when lifting the creation of regular expressions out of loops.
--      Example for what not to do:
--
--      ```ocaml
--      for i = 1 to 1000 do
--        let chunks = Pcre.split ~pat:"[ \t]+" "foo bar" in
--        (* ... *)
--      done
--      ```
--
--      Better:
--
--      ```ocaml
--      let rex = Pcre.regexp "[ \t]+" in
--      for i = 1 to 1000 do
--        let chunks = Pcre.split ~rex "foo bar" in
--        (* ... *)
--      done
--      ```
--
--The provided functions use optional arguments with intuitive defaults.  For
--example, the `Pcre.split`-function will assume whitespace as pattern.  The
--`examples`-directory contains a few example applications demonstrating the
--functionality of PCRE-OCaml.
--
--### Contact Information and Contributing
--
--Please submit bugs reports, feature requests, contributions and similar to
--the [GitHub issue tracker](https://github.com/mmottl/pcre-ocaml/issues).
--
--Up-to-date information is available at: <https://mmottl.github.io/pcre-ocaml>
-diff --git a/bundles/pcre/pcre-ocaml/dune b/bundles/pcre/pcre-ocaml/dune
-deleted file mode 100644
-index 66984ad7e..000000000
---- a/bundles/pcre/pcre-ocaml/dune
-+++ /dev/null
-@@ -1,4 +0,0 @@
--(env
--  (dev (flags (:standard -w -9 -principal)))
--  (release (ocamlopt_flags (:standard -O3)))
--)
-diff --git a/bundles/pcre/pcre-ocaml/dune-project b/bundles/pcre/pcre-ocaml/dune-project
-deleted file mode 100644
-index e14ceb0d1..000000000
---- a/bundles/pcre/pcre-ocaml/dune-project
-+++ /dev/null
-@@ -1,2 +0,0 @@
--(lang dune 1.1)
--(name pcre)
-diff --git a/bundles/pcre/pcre-ocaml/examples/Makefile b/bundles/pcre/pcre-ocaml/examples/Makefile
-deleted file mode 100644
-index 540bc9f8b..000000000
---- a/bundles/pcre/pcre-ocaml/examples/Makefile
-+++ /dev/null
-@@ -1,9 +0,0 @@
--TARGETS = $(addsuffix .bc, cloc count_hash pcregrep subst)
--
--.PHONY: all clean
--
--all:
--	@dune build $(TARGETS)
--
--clean:
--	@dune clean
-diff --git a/bundles/pcre/pcre-ocaml/examples/README.md b/bundles/pcre/pcre-ocaml/examples/README.md
-deleted file mode 100644
-index 1916310b3..000000000
---- a/bundles/pcre/pcre-ocaml/examples/README.md
-+++ /dev/null
-@@ -1,28 +0,0 @@
--## Examples
--
--### cloc
--
--This program reads C-sources from stdin and prints them to stdout with
--comments and empty lines removed.  Useful for counting LOCs.
--
--### count_hash
--
--This program reads text from stdin, counts all equal words that are separated by
--whitespace and prints the result to stdout.
--
--### pcregrep
--
--A grep-like program using Perl-compatible regular expressions.  Start the
--program with argument `-help` to see what it does!
--
--### subst
--
--Substitutes text in files using Perl-compatible regular expressions and
--substitution patterns.  Start the program with argument `-help` to see what it
--does!
--
--Example invocation:
--
--```sh
--subst '([Tt])ermcap' '$1ermCap' < /etc/termcap
--```
-diff --git a/bundles/pcre/pcre-ocaml/examples/dune b/bundles/pcre/pcre-ocaml/examples/dune
-deleted file mode 100644
-index 729c6e4d1..000000000
---- a/bundles/pcre/pcre-ocaml/examples/dune
-+++ /dev/null
-@@ -1,4 +0,0 @@
--(executables
--  (names cloc count_hash pcregrep subst)
--  (libraries pcre)
--)
-diff --git a/bundles/pcre/pcre-ocaml/examples/pcregrep.ml b/bundles/pcre/pcre-ocaml/examples/pcregrep.ml
-deleted file mode 100644
-index 1c31528e5..000000000
---- a/bundles/pcre/pcre-ocaml/examples/pcregrep.ml
-+++ /dev/null
-@@ -1,113 +0,0 @@
--open Pcre
--open Printf
--
--let filenames      = ref true
--and filenames_only = ref false
--and count_only     = ref false
--and invert         = ref false
--and number         = ref false
--and silent         = ref false
--and whole_lines    = ref false
--
--let parse_args () =
--  let ignore_case = ref false
--
--  and pat    = ref None
--  and files  = ref [] in
--
--  let c = "-c", Arg.Set count_only, "Count lines only."
--  and h = "-h", Arg.Clear filenames,
--          "Suppress printing of filenames when searching multiple files."
--  and i = "-i", Arg.Set ignore_case, "Ignore case."
--  and l = "-l", Arg.Set filenames_only,
--          "Only print names of files containing matching lines (once)."
--  and n = "-n", Arg.Set number,
--          "Precede each line by its line number in the file."
--  and s = "-s", Arg.Set silent,
--          "Display nothing but error messages. Exit status indicates match."
--  and v = "-v", Arg.Set invert,
--          "Invert sense of the match: finds nonmatching lines."
--  and x = "-x", Arg.Set whole_lines,
--          "Force the pattern to be anchored and to match the entire line."
--  and usage =
--    "Usage: pcregrep [options] pattern [file] ...\n\n\
--     Searches files for character patterns.\n"
--  and anon_arg arg =
--    if !pat = None then pat := Some arg
--    else files := arg :: !files in
--
--  let args = [c; h; i; l; n; s; v; x] in
--  Arg.parse args anon_arg usage;
--
--  let flags =
--    let flag_list = if !ignore_case then [`CASELESS] else [] in
--    if !whole_lines then `ANCHORED :: flag_list else flag_list in
--
--  let rex = 
--    match !pat with
--    | Some pat -> regexp ~flags pat
--    | None -> eprintf "%s: not enough arguments!\n" Sys.argv.(0);
--              Arg.usage args usage; exit 2 in
--  rex, List.rev !files
--
--let _ =
--  let rex, files = parse_args ()
--  and rfl = rflags [] in
--
--  let _, ovector = make_ovector rex in
--
--  let pcregrep file name =
--    let ret_code = ref 1
--    and linenumber = ref 0
--    and count = ref 0
--
--    and stdin_print_name () =
--      match name with
--      | Some filename -> print_endline filename
--      | None -> print_endline "<stdin>"
--
--    and print_name () =
--      match name with Some name -> printf "%s:" name | None -> () in
--
--    let try_match line =
--      let matched =
--        try
--          unsafe_pcre_exec rfl rex ~pos:0 ~subj_start:0 ~subj:line ovector None;
--          if !whole_lines && ovector.(1) <> String.length line then false
--          else true
--        with Not_found -> false in
--
--      incr linenumber;
--
--      if matched <> !invert then begin
--        if !count_only then incr count
--        else if !filenames_only then begin stdin_print_name (); raise Exit end
--        else if !silent then raise Exit
--        else begin
--          print_name ();
--          if !number then printf "%d:" !linenumber;
--          print_endline line
--        end;
--        ret_code := 0 end in
--
--    try
--      foreach_line ~ic:file try_match;
--      if !count_only then begin
--        print_name ();
--        printf "%d\n" !count end;
--      !ret_code
--    with Exit -> 0 in
--
--  if files = [] then exit (pcregrep stdin None);
--
--  if List.length files = 1 then filenames := false;
--  if !filenames_only then filenames := true;
--
--  let collect ret_code filename =
--    try
--      let file = open_in filename in
--      let frc = pcregrep file (if !filenames then Some filename else None) in
--      close_in file;
--      if frc = 0 && ret_code = 1 then 0 else ret_code
--    with Sys_error msg -> prerr_endline msg; 2 in
--  exit (List.fold_left collect 1 files)
-diff --git a/bundles/pcre/pcre-ocaml/examples/subst.ml b/bundles/pcre/pcre-ocaml/examples/subst.ml
-deleted file mode 100644
-index 24701dda1..000000000
---- a/bundles/pcre/pcre-ocaml/examples/subst.ml
-+++ /dev/null
-@@ -1,54 +0,0 @@
--open Pcre
--
--let parse_args () =
--  let quick       = ref false
--  and first       = ref false
--  and ignore_case = ref false
--  and offset      = ref 0
--
--  and pat    = ref None
--  and substr = ref None in
--
--  let q   = "-q", Arg.Set quick,
--            "Quick replacement. Interpretes substitution as plain text."
--  and f   = "-f", Arg.Set first, "Replace first occurrence in line only."
--  and i   = "-i", Arg.Set ignore_case, "Ignore case."
--  and ofs = "-ofs", Arg.Int (fun n -> offset := n),
--            "Start matching at column n."
--
--  and usage =
--    "Usage: subst [-q] [-f] [-i] [-ofs offset] pattern substitution\n\n\
--     Reads lines from standard input and replaces occurrences of\n\
--     the PERL-style regular expression \"pattern\" with \"substitution\",\n\
--     printing the result to standard output.\n\
--     In default mode the contents of \"substitution\" will be interpreted\n\
--     similarly to its equivalent in PERL.\n"
--
--  and anon_arg arg =
--    match !pat, !substr with
--    | None, _ -> pat := Some arg
--    | _, None -> substr := Some arg
--    | _       -> raise (Arg.Bad "too many arguments!") in
--
--  let args = [q; f; i; ofs] in
--  Arg.parse args anon_arg usage;
--
--  let flags = if !ignore_case then [`CASELESS] else [] in
--
--  let rex, sstr =
--    match !pat, !substr with
--      | Some rex, Some sstr -> regexp ~flags rex, sstr
--      | _ -> prerr_endline (Sys.argv.(0) ^ ": not enough arguments!");
--             Arg.usage args usage; exit 1 in
--
--  match !quick, !first with
--  | false, false -> fun s -> replace ~rex ~pos:!offset ~templ:sstr s
--  | true, false  -> fun s -> qreplace ~rex ~pos:!offset ~templ:sstr s
--  | false, true  -> fun s -> replace_first ~rex ~pos:!offset ~templ:sstr s
--  | true, true   -> fun s -> qreplace_first ~rex ~pos:!offset ~templ:sstr s
--
--let _ =
--  let substitute = parse_args () in
--  foreach_line (fun line ->
--    try print_endline (substitute line)
--    with Invalid_argument _ -> print_endline line)
-diff --git a/bundles/pcre/pcre-ocaml/pcre.opam b/bundles/pcre/pcre-ocaml/pcre.opam
-deleted file mode 100644
-index 4ef1e77e9..000000000
---- a/bundles/pcre/pcre-ocaml/pcre.opam
-+++ /dev/null
-@@ -1,27 +0,0 @@
--opam-version: "2.0"
--maintainer: "Markus Mottl <markus.mottl@gmail.com>"
--authors: [ "Markus Mottl <markus.mottl@gmail.com>" ]
--license: "LGPL-2.1+ with OCaml linking exception"
--homepage: "https://mmottl.github.io/pcre-ocaml"
--doc: "https://mmottl.github.io/pcre-ocaml/api"
--dev-repo: "git+https://github.com/mmottl/pcre-ocaml.git"
--bug-reports: "https://github.com/mmottl/pcre-ocaml/issues"
--
--build: [
--  ["dune" "subst"] {pinned}
--  ["dune" "build" "-p" name "-j" jobs]
--]
--
--depends: [
--  "ocaml" {>= "4.04"}
--  "dune" {build & >= "1.4.0"}
--  "conf-libpcre" {build}
--  "base" {build}
--  "base-bytes"
--]
--
--synopsis: "Bindings to the Perl Compatibility Regular Expressions library"
--
--description: """
--pcre-ocaml offers library functions for string pattern matching and
--substitution, similar to the functionality offered by the Perl language."""
-diff --git a/bundles/pcre/pcre-ocaml/pre-v7.3.0-CHANGES.txt b/bundles/pcre/pcre-ocaml/pre-v7.3.0-CHANGES.txt
-deleted file mode 100644
-index 9bc9875f0..000000000
---- a/bundles/pcre/pcre-ocaml/pre-v7.3.0-CHANGES.txt
-+++ /dev/null
-@@ -1,698 +0,0 @@
--2016-02-25:  Minor version release v7.2.3:
--
--               Fixed callout bug introduced with v7.2.0.
--
--             Thanks to Raman Varabets for the bug report!
--
--2016-02-23:  Fixed linking problem with old versions of PCRE (< 8.20).
--
--             Fixed backward compatibility issue with OCaml <= 3.12.
--
--2016-02-22:  Fixed a subgroup matching bug.
--
--             Thanks to Cheng Lou for the bug report!
--
--2015-08-21:  Made GC less aggressive reclaiming regexps and chartables.
--
--2014-12-10:  Fixed another limit handling bug in the full_split function.
--
--2014-12-02:  Fixed a limit handling bug in the full_split function.
--
--             Thanks to Rudi Grinberg <rudi.grinberg@gmail.com> for the report!
--
--2014-10-23:  Fixed string handling for new OCaml version 4.02 (String/Bytes
--             modules).  Requires new findlib version (>= 1.5).
--
--2014-07-06:  Moved to GitHub.
--
--2014-06-04:  Multiple bug fixes:
--
--               * Allcation bug when performing callouts
--               * Unprotected root when performing callouts
--               * More portable offset copying in the C-stubs
--               * Fixed a PERL-compatibility bug in the splitting routines
--
--            The bug fixes required a minor API-change in an unsafe function,
--            which is almost surely not directly called by any users.
--
--2012-07-20:  Downgraded findlib version requirement to support the Debian
--             testing branch.
--
--             Added --with-pcre-config flag to configure location of PCRE
--             configuration generator.
--
--2012-07-15:  New major release version 7.0.0:
--
--               * Upgraded to OCaml 4.00
--               * Switched to Oasis for packaging
--               * Switched to OCamlBuild for the build process
--               * Rewrote README in Markdown
--               * Added stricter compilation flags
--               * Minor bugfixes
--
--2012-01-04:  Fixed native code debug build target by updating OCamlMakefile.
--
--             Thanks to Stéphane Glondu <glondu@debian.org> for the patch!
--
--2011-12-15:   Fixed a Windows portability bug in the C-bindings.
--
--             Thanks to Evgenii Lepikhin <johnlepikhin@gmail.com> for the patch!
--
--2011-11-09:  Updated OCamlMakefile to fix linking order.
--
--2011-01-16:  Added support for limit recursion flag.
--
--             Thanks to Delphin Lecucq <Delphin.LECUCQ@3ds.com> for the patch!
--
--2010-10-31:  Improved Windows support with MSVC.
--
--             Thanks to Sylvain Le Gall <sylvain@le-gall.net> for the patch!
--
--2010-04-01:  Added new function:
--
--               * regexp_or
--
--2009-06-20:  Fixed bug in configuration functions that could lead to a segfault.
--
--             Thanks to Gerd Stolpmann <gerd@gerd-stolpmann.de> for the patch!
--
--2009-05-07:  Changed API wrt. error handling and thus made a major release.
--
--             Improved behavior in the presence of recursion limit errors.
--             Thanks to Martin Jambon <martinj@mylife.com> for this patch!
--
--2009-04-23:  Fixed build problem on MinGW.
--
--             Thanks to Gerd Stolpmann <gerd@gerd-stolpmann.de> for the patch!
--
--2009-03-08:  Fixed build problem on Mac OS X with macports.
--
--             Thanks to Ralph Douglass <ralph@grayskies.net> for the
--             initial patch.
--
--             Update OCamlMakefile.
--
--             Improved Godi-distribution.
--
--2008-05-06:  Fixed build problem with newer versions of PCRE.
--
--2008-03-14:  Synced with Jane Street tree.
--
--2008-01-25:  Added new function:
--
--               * names
--
--             This function returns the names of all named substrings in a
--             regular expression.
--
--             Thanks to Benedikt Grundmann <bgrundmann@janestreet.com>
--             for the patch!
--
--2007-07-12:  Improved build scripts for Windows.
--
--             Thanks to Christophe Troestler
--             <Christophe.Troestler@umh.ac.be> for the patch!
--
--2007-07-12:  Improved documentation for Win32 builds, and added some build
--             scripts usable on Windows.
--
--             Thanks to Christophe Troestler
--             <Christophe.Troestler@umh.ac.be> for this contribution!
--
--2007-04-23:  callback_exn -> caml_callback_exn.
--
--             Updated OCamlMakefile.
--
--2006-11-22:  Updated OCamlMakefile.
--
--2006-06-11:  Updated to pcre-5.0!
--
--             New representation for callbacks: they now take only one
--             argument (a record of the callback data).
--
--             Added partial matching and auto callouts.
--
--2006-01-16:  Updated OCamlMakefile.
--
--             Removed a superfluous binding.
--
--2005-08-18:  Fixed a small compilation problem on rare platforms by
--             upgrading OCamlMakefile.
--
--2005-06-08:  Relaxed license.  Fixed copyright headers.
--
--2005-05-31:  Fixed some uncleanliness reported by Saffire (FFI-type checker).
--
--2004-09-17:  Fixed a bug concerning null patterns in exec_all (extract_all
--             and extract_all_opt are also affected).
--
--             Updated OCamlMakefile.
--
--2004-05-19:  Updated Makefile.mingw.
--             Thanks to Jeff Henrikson <jehenrik@yahoo.com> for the patch!
--
--             Updated OCamlMakefile.
--
--2004-04-29:  Changed behaviour of "get_substring"!!!
--
--             It now does not return the empty string anymore if an
--             accessed substring was not captured.  It raises the exception
--             "Not_found" instead.
--
--             Three new functions:
--
--               * get_opt_substrings
--               * extract_opt
--               * extract_all_opt
--
--             These behave like the functions without "opt", but return
--             "Some substring" if a substring was captured, and "None"
--             otherwise.
--
--2004-04-27:  Updated OCamlMakefile.
--
--2004-04-24:  Updated OCamlMakefile.
--
--2004-03-28:  Changed interface to build-time configuration functions
--             of PCRE.
--
--             Updated OCamlMakefile.
--
--2004-02-21:  Added CAMLprim in the C-interface where appropriate.
--
--2004-02-08:  Fixed a minor bug concerning returning unit values from C.
--
--2004-01-31:  Added pcre_make.win32/Makefile.mingw. Thanks to Jeffrey
--             Henrikson <JEFHEN@SAFECO.com> for this contribution!
--
--             Update OCamlMakefile.
--
--2004-01-13:  Updated pcre_make.win32/pcre.h.
--
--2003-12-30:  Fixed documentation.
--
--2003-12-21:  Updated to pcre-4.5!
--
--             New function:
--
--               * config_stackrecurse
--
--             New exception:
--
--               * BadUTF8Offset
--
--             Updated OCamlMakefile.
--
--2003-12-19:  Fixed a small (but probably unnoticable) bug concerning
--             allocation of optional values in the C-stubs.
--
--2003-12-12:  Updated OCamlMakefile. Renamed stubs (invisible to users).
--
--2003-11-16:  Updated pcre_make.win32/pcre.h to reflect newest PCRE-version.
--             May help Windows users.
--
--2003-10-08:  Upgraded to pcre-4.4!
--
--             New flag for compiling patterns: NO_UTF8_CHECK
--             New exception: BadUTF8
--
--             Updated OCamlMakefile.
--
--2003-09-30:  Fixed a bug in the documentation.
--             Updated OCamlMakefile.
--
--2003-06-17:  Fixed a bug in the documentation.
--             Updated OCamlMakefile.
--
--2003-05-29:  Updated to pcre-4.3!
--
--             Major change: callouts are now fully supported! This allows
--             the matching engine call OCaml-code while matching - quite
--             powerful! Please see the interface specification for more
--             information.
--
--             Many small changes (improvements) in C-code. Updated
--             documentation.
--
--2003-04-08:  Updated OCamlMakefile. Reformatted documentation.
--
--2003-03-20:  Added new function "get_subject". Patched OCamlMakefile.
--
--2003-03-18:  Major update: upgraded to pcre-4.1!
--
--             Better UTF8-support.
--             New flag "NO_AUTO_CAPTURE".
--
--             New values:
--
--               * config_utf8
--               * config_newline
--               * config_link_size
--               * config_match_limit
--
--             Renamed all occurrences of "firstchar" to "firstbyte".
--
--             New functions:
--
--               * studysize
--               * namecount
--               * nameentrysize
--               * get_stringnumber
--
--             Updated OCamlMakefile.
--
--2003-01-07:  Updated OCamlMakefile to make use of "findlib".
--
--             Added support for UTF-8 character encodings.
--
--             Better installation and documentation for Win32.
--
--             Thanks to Artem Prisyznuk <tema@sit.kiev.ua> for the above
--             patches!
--
--2002-12-14:  Fixed a bug concerning zero-sized matches effecting
--             "replace", "qreplace", "substitute_substrings" and
--             "substitute".
--
--             Updated OCamlMakefile.
--
--2002-12-08:  Improved documentation of "pcre_exec".
--
--2002-11-24:  Fixed a bug in "full_split" concerning matched subgroups.
--
--2002-11-12:  Added a new function "extract_all" (see interface
--             documentation).
--
--2002-08-16:  Fixed a bug in the "split"-function:
--
--             The Perl-splitting semantics was not completely adhered to:
--             leading whitespace was stripped after the matching process
--             rather than before, which lead to incompatible behaviour
--             when a maximum bound was used.
--
--             Thanks to Yutaka Oiwa <oiwa@yl.is.s.u-tokyo.ac.jp> for the
--             bug report!
--
--             Updated OCamlMakefile.
--
--2002-07-31:  Fixed a bug in the following functions:
--
--               * replace
--               * qreplace
--               * substitute_substrings
--
--             Transformed most part of the library to make it slightly
--             more efficient and simple. The interface is still the same!
--
--             Updated OCamlMakefile + documentation.
--
--2002-07-15:  Fixed a mistake in the documentation.
--
--2002-05-05:  Fixed a bug with the generation of byte-code libraries that
--             dynamically link the PCRE.
--
--2002-05-01:  Removed C-library from distribution! Users must install it
--             on their own now. Reorganized whole distribution and updated
--             OCamlMakefile again for better support of dynamic and/or
--             static libraries.
--
--2002-04-30:  Updated OcamlMakefile: it does not ask for confirmation
--             during installation anymore!
--
--2002-03-06:  Upgraded to pcre-3.9. This should not change anything for
--             OCaml-users.
--
--2002-03-01:  Updated OcamlMakefile.
--
--2002-02-24:  Separated compilation of library and examples to prevent
--             confusions when the library needs to be installed before
--             one can build the examples.
--
--2002-02-15:  Fixed a bug in the pcre_exec-function which was introduced
--             ten days ago during correction of another bug (thanks to
--             Gerd Stolpmann for the report!).
--
--2002-02-15:  Added the option to compile the library statically only.
--
--             Updated INSTALL-notes to explain possible installation
--             problems associated with support of dynamic linking.
--
--             Added META-file for findlib.
--
--2002-02-12:  Rewrote interface documentation to support OCamldoc.
--
--             Fixed a portability bug with shared libraries.
--
--2002-02-10:  Removed project from Sourceforge for simpler maintainance.
--
--2002-02-07:  Important news: library is linked dynamically now by default.
--
--2002-02-06:  Fixed a stupid bug affecting the following functions
--             (thanks to Jacek Chrzaszcz for the bug report!):
--
--               * num_of_subs
--               * get_substring
--               * get_substring_ofs
--               * get_substrings
--               * extract
--
--             Also done: converted literal pattern strings in the library
--             and the cloc-example so that the escape char (backslash) does
--             not cause warnings anymore with the new OCaml-release. The
--             latter is more paranoid about unknown escape combinations,
--             requiring the user to add extra backslashes.
--
--2002-01-07:  Fixed a stupid bug: the position argument (offset) was
--             not correctly handled in replacement and substitution
--             functions, leading to wrong results. As it seems, people
--             seldom use arguments other than zero...
--
--             The "subst"-example now assumes that offsets other than zero
--             should not lead to an error if it exceeds the line length.
--             The line is just copied instead.
--
--2001-12-28:  Added README.win32 (courtesy of John W. Small).
--
--             Updated README so that it is generated by Hevea.
--
--2001-11-19:  Upgraded to the newest release of the underlying C-library
--             (PCRE-3.7).
--
--             Added a tiny patch to satisfy the Visual C++ compiler under
--             W2K (thanks to John W. Small!).
--
--             Updated contact address.
--
--2001-11-17:  Updated OcamlMakefile.
--
--2001-09-15:  Upgraded to the newest release of the underlying C-library
--             (PCRE-3.5).
--
--             Added a new function: substitute_substrings
--
--             It is similar to "substitute", but takes the full substring
--             information of the match rather than the matching string.
--             Thanks to Patrick M. Doane for proposing this missing feature!
--
--2001-09-07:  Updated OcamlMakefile
--
--2001-08-27:  Fixed a bug in the splitting function: leading whitespace was
--             accidently always removed when using a regular expression
--             rather than a pattern. This behaviour should only happen
--             for the default whitespace pattern, which is used if you
--             do not specify any pattern or regexp in the function call.
--
--2001-06-30:  Removed "Printexc.catch" from examples: is going to be
--             deprecated in upcoming OCaml-release.
--
--2001-05-22:  Fixed typo in documentation.
--
--2001-04-25:  Added a new function: asplit
--
--             It is identical to "split" with the exception that it
--             returns a string array instead of a string list. This makes
--             it easier for the user to access strings by index.
--
--             Added a new option to "get_substrings" and "extract": full_match
--
--             When "full_match" is true (default: yes), then the resulting
--             string array will contain the full match at index 0,
--             otherwise the result will only contain captured substrings.
--
--             Removed superfluous comments in "pcre.ml": they are already
--             present in the interface documentation anyway.
--
--2001-04-08:  Small patch that makes this library compile on OpenBSD, too.
--
--2001-01-30:  Made Makefile more general (allows simpler addition of
--             further examples).
--
--2001-01-24:  Updated OcamlMakefile: made default definition of
--             "OCAMLLIBPATH" backwards compatible again: some people
--             do not use the CVS-version of OCaml, which supports the
--             "-where"-option.  People with the new compiler will not
--             notice any effect.
--
--2001-01-06:  Added a new function: exec_all
--
--             It allows you to execute pattern matching over a whole
--             string until no more matches can be found: then it returns
--             the array of all matching "substrings". You can extract
--             subpatterns of each of those matching substrings again with
--             the usual functions.
--
--             Fixed a minor inconsistency in "next_match".
--
--2000-12-23:  Updated OcamlMakefile: makes use of the new "-where"-keyword
--             to find the path to the standard library if it is not
--             defined.
--
--2000-12-14:  Pedantry in the C-interface: added "const" qualifiers.
--
--2000-12-09:  Made some functions tail-recursive (very unlikely to cause
--             any noticable effect for most people).
--
--2000-12-02:  Cleaned up the code a bit for distribution on SourceForge.
--             Speed of some operations should be very slightly improved, too.
--
--2000-11-16:  Fixed a stupid bug that could crash your programs under rare
--             circumstances (when you use faulty regular expressions).
--
--             Added an internally used exception (InternalError) to the
--             interface of the library.  This allows the user to handle
--             the case when the C-engine exhibits undefined behaviour
--             (should never happen, anyway).
--
--2000-09-27:  Upgraded to the newest release of the underlying C-library
--             (PCRE-3.4).
--
--             See "pcre-C/ChangeLog" for more information (mostly minor
--             bugfixes).
--
--             Renamed "pgrep" to "pcregrep" to prevent name hiding on
--             Solaris (change as suggested in the C-library distribution).
--
--2000-06-24:  Updated OcamlMakefile
--
--2000-06-13:  Updated OcamlMakefile
--
--2000-06-12:  Mini-optimisation: lifted a pure value out of a function body.
--
--2000-06-11:  Updated OcamlMakefile
--
--2000-06-08:  Added installation routine + updated OcamlMakefile again:
--
--             This upgrade makes installation much easier! Read the
--             updated INSTALL-file!
--
--2000-06-07:  Updated to new OcamlMakefile
--
--2000-06-05:  Added a new function:
--
--               get_substring_ofs substrings n
--
--             This allows you to get the offset positions of the matching
--             pattern and the substrings directly from a value of type
--             "substring". See the interface documentation for details.
--
--2000-05-15:  Upgraded to the newest release of the underlying C-library
--             (PCRE-3.2).
--
--             This does not add new features, but is said to fix some
--             PERL-compatibility bugs and improves portability.
--
--2000-05-04:  Minor update of C-interface:
--
--             Use the new "hash_variant"-function to compute the hash value of
--             variants (used Callback.register before - a bit clumsy).
--
--2000-04-24:  New release: compiles with OCaml-3.00.
--
--             Lots of changes in interface! OCaml-3.00 introduced some syntax
--             changes for labels. Additionally, no keywords are allowed for
--             them.  All this required quite some renamings. I tried to stick to
--             the new labels of the "str"-library as close as makes sense.
--             Sorry for this inconvenience, but I think that adhering to some
--             "standard" is a Good Thing...
--
--             For further information on the changes, look at the documentation
--             of the interface file.
--
--2000-04-23:  Minor cleanup of C-interface:
--
--             Made local functions + variables static and moved a check for
--             error codes (lint should be happier now).
--
--2000-04-01:  Changed linking of the library again (marginally):
--
--             The new linking semantics for byte code libraries allows passing
--             of flags that are remembered. This then only requires linking
--             executables against "pcre.cma" - the C-library ("libpcre.a") will
--             be linked in automatically.
--
--2000-03-30:  Cleaned up the C-interface:
--
--             Removed a possible bug in the allocation of firstchar values.
--
--             Saner handling of polymorphic variants (not hard-wired
--             integers anymore - registered via callbacks).
--
--             Better GC-settings: much nicer to the GC now (fewer full
--             cycles - hardly more memory consumption). Should make
--             programs run slightly faster when regular expressions are
--             often allocated.
--
--             Changed linking of the library to suit the semantics of
--             the upcoming OCaml-major release (backward compatible).
--
--2000-02-07:  Changed interface of function "foreach_file":
--
--             No idea why I implemented a tuple in the interface instead of a
--             curried function. Must have been the drugs... ;-)
--
--             Former interface:
--
--               val foreach_file :
--                 string list -> (string * in_channel -> unit) -> unit
--
--             Current interface:
--
--               val foreach_file :
--                 string list -> (string -> in_channel -> unit) -> unit
--
--             Additionally, this function now also closes the file channel
--             in case of an exception. The exception gets reraised,
--             of course.
--
--2000-02-05:  Eliminated a PERL-incompatibility of the "split"-function:
--
--             When neither the pattern nor the compiled regular
--             expression are specified, "split" defaults to a whitespace
--             pattern. However, PERL additionally strips leading
--             whitespace, but *only* when in "default" mode.
--
--             This last "feature" (?) was overseen during the introduction
--             of labels and default arguments.
--
--2000-02-05:  Updated the C-library to the newest release (pcre-3.0).
--
--             This is a major release, but the changes to the OCaml-part
--             are rather small: just the functionality concerning
--             information on compiled patterns has changed.
--
--             Instead of the former "info"-function, several ones are
--             provided. I think this is the most convenient way to handle
--             this, because it does not force the user to do explicit
--             pattern matching on results: due to the number of new
--             info-options this would have been rather confusing.
--
--             Because the old PCRE-function "pcre_info" is obsolete,
--             I chose to drop its OCaml-interface completely. I do not
--             think that it is an often used part, anyway.
--
--             See the interface file and the ChangeLog + documentation
--             of the C-library to see, what has changed in detail.
--
--             The other few changes just marginally effect efficiency. One
--             bug was present in the last release in the "info"-part
--             (polymorphic variants were not correctly represented).
--             This has changed anyway and should work fine now.
--
--2000-01-10:  "foreach_line" uses stdin as labeled (label: 'in') default
--             argument now.
--
--1999-12-29:  Lots of changes:
--
--             * Uses the new features of OCaml 2.99:
--
--               Labeled parameters and default arguments for much more
--               convenience. E.g. write
--
--                 split pos:1 "foo bar"
--
--               to get the list ["oo"; "bar"].
--
--               Polymorphic variants for passing options: this change allows,
--               for example, using the data constructor "ANCHORED" for both
--               compiling flags and at matching time instead of "C_ANCHORED"
--               and "R_ANCHORED".
--
--             * Got rid of all the superfluous shortcuts, like "bounded_psplit"
--               and the like. Labeled parameters are much more readable and
--               convenient.
--
--             * Removed the functions compatible to the "Str"-module. It's
--               probably rather confusing for people to see two different kinds
--               of implementations.
--
--             * Renamed functions due to the use of labels and the removing of
--               the obsolete compatibility functions.
--
--             * Updated documentation with more details on using the library.
--
--1999-12-21:  Small change (2 chars...) to make the C-interface compile with
--             the newest release (OCaml 2.99).
--
--1999-09-27:  Fixed a bug which occurs, when replacements or substitutions
--             in strings are longer than the subject string itself.
--             This concerns functions "replace_all", "qreplace_all" and
--             "substitute_all" + their variants.
--
--             THANKS to GERD STOLPMANN (Gerd.Stolpmann@darmstadt.netsurf.de)
--             for finding another bug!
--
--1999-09-21:  Fixed some bugs in "pcre_intf.c":
--
--             "Store_field" was used inappropriately throughout the file,
--             which could lead to segfaults in the garbage collector. This
--             was corrected by using the "Field"-macro where appropriate.
--
--             Protected an input parameter from being reclaimed too early.
--
--             Initialized a field before throwing an exception to please
--             the GC.
--
--             The GC should be happy now...
--
--             THANKS to GERD STOLPMANN (Gerd.Stolpmann@darmstadt.netsurf.de)
--             for the patch!
--
--1999-08-31:  Updated to pcre-2.08 - this should fix some bugs. See
--             "pcre-C/ChangeLog" for details.
--
--             Renamed directory "pcre-C-2.07" to "pcre-C" to allow for
--             easier upgrading.
--
--             Added CVS-info to sources.
--
--1999-08-24:  Updated to pcre-2.07. Splitting is 100% PERL-compatible now.
--             New runtime option: NOTEMPTY (see interface for details).
--
--             Two additional examples: cloc and count_hash.
--
--             New functions: sregexpo, sregexp, sregexp_case_fold.
--
--1999-08-02:  Exception handling more regular now:
--
--             Raises [Invalid_argument] instead of [Failure] where
--             appropriate.
--             Raises [InternalError] if C-library exhibits undefined
--             behaviour (has never happened so far).
--
--             Updated comments.
--
--1999-07-30:  Bugfix in "pcre_intf.c":
--
--             "pcre_ocaml" should work now on 64-bit architectures...
--
--1999-07-29:  Small fix in "pcre_intf.c":
--
--             strict compilers (gcc is not very strict) otherwise complain
--             about undefined behaviour in a certain line.
--
--             Explicitely mention all include files.
--             Removed unused variable.
--
--             Also moved a line for efficiency...
--
--1999-07-28:  First release.
-diff --git a/bundles/pcre/pcre-ocaml/src/.gitignore b/bundles/pcre/pcre-ocaml/src/.gitignore
-deleted file mode 100644
-index 7da7cb2d0..000000000
---- a/bundles/pcre/pcre-ocaml/src/.gitignore
-+++ /dev/null
-@@ -1 +0,0 @@
--pcre_stubs.c
-\ No newline at end of file
-diff --git a/bundles/pcre/pcre-ocaml/src/Makefile b/bundles/pcre/pcre-ocaml/src/Makefile
-deleted file mode 100644
-index 724653615..000000000
---- a/bundles/pcre/pcre-ocaml/src/Makefile
-+++ /dev/null
-@@ -1,9 +0,0 @@
--TARGETS = pcre.cma libpcre_stubs.a
--
--.PHONY: all clean
--
--all:
--	@dune build $(TARGETS)
--
--clean:
--	@dune clean
-diff --git a/bundles/pcre/pcre-ocaml/src/config/discover.ml b/bundles/pcre/pcre-ocaml/src/config/discover.ml
-deleted file mode 100644
-index 01fbfab0a..000000000
---- a/bundles/pcre/pcre-ocaml/src/config/discover.ml
-+++ /dev/null
-@@ -1,15 +0,0 @@
--open Base
--
--let () =
--  let module C = Configurator.V1 in
--  C.main ~name:"pcre" (fun c ->
--    let default : C.Pkg_config.package_conf = {
--      libs = ["-lpcre"];
--      cflags = []
--    } in
--    let conf =
--      Option.value_map (C.Pkg_config.get c) ~default ~f:(fun pc ->
--        Option.value (C.Pkg_config.query pc ~package:"libpcre") ~default)
--    in
--    C.Flags.write_sexp "c_flags.sexp" conf.cflags;
--    C.Flags.write_sexp "c_library_flags.sexp" conf.libs)
-diff --git a/bundles/pcre/pcre-ocaml/src/config/dune b/bundles/pcre/pcre-ocaml/src/config/dune
-deleted file mode 100644
-index dbea8ff91..000000000
---- a/bundles/pcre/pcre-ocaml/src/config/dune
-+++ /dev/null
-@@ -1,4 +0,0 @@
--(executables
--  (names discover)
--  (libraries base dune.configurator)
--)
-diff --git a/bundles/pcre/pcre-ocaml/src/dune b/bundles/pcre/pcre-ocaml/src/dune
-deleted file mode 100644
-index a0bd636d7..000000000
---- a/bundles/pcre/pcre-ocaml/src/dune
-+++ /dev/null
-@@ -1,16 +0,0 @@
--(library
--  (public_name pcre)
--  (c_names pcre_stubs)
--  (c_flags (
--    (:include c_flags.sexp) -g -O2 -fPIC -DPIC
--    ; NOTE: for debugging before releases
--    ; -Wall -pedantic -Wextra -Wunused -Wno-long-long -Wno-keyword-macro
--  ))
--  (c_library_flags (:include c_library_flags.sexp))
--)
--
--(rule
--  (targets c_flags.sexp c_library_flags.sexp)
--  (deps (:discover config/discover.exe))
--  (action (run %{discover}))
--)
-diff --git a/bundles/pcre/pcre-ocaml/src/pcre.ml.in b/bundles/pcre/pcre-ocaml/src/pcre.ml.in
-deleted file mode 100644
-index 573460e4e..000000000
---- a/bundles/pcre/pcre-ocaml/src/pcre.ml.in
-+++ /dev/null
-@@ -1,1055 +0,0 @@
--(*
--   PCRE-OCAML - Perl Compatibility Regular Expressions for OCaml
--
--   Copyright (C) 1999-  Markus Mottl
--   email: markus.mottl@gmail.com
--   WWW:   http://www.ocaml.info
--
--   This library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
--
--   This library 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
--   Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public
--   License along with this library; if not, write to the Free Software
--   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--*)
--
--open Stdcompat
--
--(* Public exceptions and their registration with the C runtime *)
--
--type error =
--  | Partial
--  | BadPartial
--  | BadPattern of string * int
--  | BadUTF8
--  | BadUTF8Offset
--  | MatchLimit
--  | RecursionLimit
--  | InternalError of string
--
--exception Error of error
--exception Backtrack
--exception Regexp_or of string * error
--
--(* Puts exceptions into global C-variables for fast retrieval *)
--external pcre_ocaml_init : unit -> unit = "pcre_ocaml_init"
--
--(* Registers exceptions with the C runtime and caches polymorphic variants *)
--let () =
--  Callback.register_exception "Pcre.Error" (Error (InternalError ""));
--  Callback.register_exception "Pcre.Backtrack" Backtrack;
--  pcre_ocaml_init ()
--
--
--(* Compilation and runtime flags and their conversion functions *)
--
--type icflag = int
--type irflag = int
--
--(* Compilation flags *)
--
--type cflag =
--  [
--  | `CASELESS
--  | `MULTILINE
--  | `DOTALL
--  | `EXTENDED
--  | `ANCHORED
--  | `DOLLAR_ENDONLY
--  | `EXTRA
--  | `UNGREEDY
--  | `UTF8
--  | `NO_UTF8_CHECK
--  | `NO_AUTO_CAPTURE
--  | `AUTO_CALLOUT
--  | `FIRSTLINE
--  ]
--
--let int_of_cflag = function
--  | `CASELESS -> 0x0001
--  | `MULTILINE -> 0x0002
--  | `DOTALL -> 0x0004
--  | `EXTENDED -> 0x0008
--  | `ANCHORED -> 0x0010
--  | `DOLLAR_ENDONLY -> 0x0020
--  | `EXTRA -> 0x0040
--  | `UNGREEDY -> 0x0200
--  | `UTF8 -> 0x0800
--  | `NO_AUTO_CAPTURE -> 0x1000
--  | `NO_UTF8_CHECK -> 0x2000
--  | `AUTO_CALLOUT -> 0x4000
--  | `FIRSTLINE -> 0x40000
--
--let coll_icflag icflag flag = int_of_cflag flag lor icflag
--let cflags flags = List.fold_left coll_icflag 0 flags
--
--let cflag_of_int = function
--  | 0x0001 -> `CASELESS
--  | 0x0002 -> `MULTILINE
--  | 0x0004 -> `DOTALL
--  | 0x0008 -> `EXTENDED
--  | 0x0010 -> `ANCHORED
--  | 0x0020 -> `DOLLAR_ENDONLY
--  | 0x0040 -> `EXTRA
--  | 0x0200 -> `UNGREEDY
--  | 0x0800 -> `UTF8
--  | 0x1000 -> `NO_AUTO_CAPTURE
--  | 0x2000 -> `NO_UTF8_CHECK
--  | 0x4000 -> `AUTO_CALLOUT
--  | 0x40000 -> `FIRSTLINE
--  | _ -> failwith "Pcre.cflag_list: unknown compilation flag"
--
--let all_cflags =
--  [
--    0x0001; 0x0002; 0x0004; 0x0008; 0x0010; 0x0020;
--    0x0040; 0x0200; 0x0800; 0x1000; 0x2000; 0x4000; 0x40000;
--  ]
--
--let cflag_list icflags =
--  let coll flag_list flag =
--    if icflags land flag <> 0 then cflag_of_int flag :: flag_list
--    else flag_list in
--  List.fold_left coll [] all_cflags
--
--
--(* Runtime flags *)
--
--type rflag =
--  [
--  | `ANCHORED
--  | `NOTBOL
--  | `NOTEOL
--  | `NOTEMPTY
--  | `PARTIAL
--  ]
--
--let int_of_rflag = function
--  | `ANCHORED -> 0x0010
--  | `NOTBOL -> 0x0080
--  | `NOTEOL -> 0x0100
--  | `NOTEMPTY -> 0x0400
--  | `PARTIAL -> 0x8000
--
--let coll_irflag irflag flag = int_of_rflag flag lor irflag
--let rflags flags = List.fold_left coll_irflag 0 flags
--
--let rflag_of_int = function
--  | 0x0010 -> `ANCHORED
--  | 0x0080 -> `NOTBOL
--  | 0x0100 -> `NOTEOL
--  | 0x0400 -> `NOTEMPTY
--  | 0x8000 -> `PARTIAL
--  | _ -> failwith "Pcre.rflag_list: unknown runtime flag"
--
--let all_rflags = [0x0010; 0x0080; 0x0100; 0x0400; 0x8000]
--
--let rflag_list irflags =
--  let coll flag_list flag =
--    if irflags land flag <> 0 then rflag_of_int flag :: flag_list
--    else flag_list in
--  List.fold_left coll [] all_rflags
--
--
--(* Information on the PCRE-configuration (build-time options) *)
--
--external pcre_version : unit -> string = "pcre_version_stub"
--
--external pcre_config_utf8 : unit -> bool = "pcre_config_utf8_stub" @noalloc@
--
--external pcre_config_newline :
--  unit -> char = "pcre_config_newline_stub" @noalloc@
--
--external pcre_config_link_size : unit -> (int @untagged@)
--  = "pcre_config_link_size_stub_bc" "pcre_config_link_size_stub" @noalloc@
--
--external pcre_config_match_limit :
--  unit -> (int @untagged@)
--  = "pcre_config_match_limit_stub_bc" "pcre_config_match_limit_stub" @noalloc@
--
--external pcre_config_match_limit_recursion : unit -> (int @untagged@)
--  =
--  "pcre_config_match_limit_recursion_stub_bc"
--  "pcre_config_match_limit_recursion_stub"
--  @noalloc@
--
--external pcre_config_stackrecurse :
--  unit -> bool = "pcre_config_stackrecurse_stub" @noalloc@
--
--let version = pcre_version ()
--let config_utf8 = pcre_config_utf8 ()
--let config_newline = pcre_config_newline ()
--let config_link_size = pcre_config_link_size ()
--let config_match_limit = pcre_config_match_limit ()
--let config_match_limit_recursion = pcre_config_match_limit_recursion ()
--let config_stackrecurse = pcre_config_stackrecurse ()
--
--
--(* Information on patterns *)
--
--type firstbyte_info =
--  [ `Char of char
--  | `Start_only
--  | `ANCHORED ]
--
--type study_stat =
--  [ `Not_studied
--  | `Studied
--  | `Optimal ]
--
--type regexp
--
--external options : regexp -> (icflag @untagged@)
--  = "pcre_options_stub_bc" "pcre_options_stub"
--
--external size : regexp -> (int @untagged@)
--  = "pcre_size_stub_bc" "pcre_size_stub"
--
--external studysize : regexp -> (int @untagged@)
--  = "pcre_studysize_stub_bc" "pcre_studysize_stub"
--
--external capturecount : regexp -> (int @untagged@)
--  = "pcre_capturecount_stub_bc" "pcre_capturecount_stub"
--
--external backrefmax : regexp -> (int @untagged@)
--  = "pcre_backrefmax_stub_bc" "pcre_backrefmax_stub"
--
--external namecount : regexp -> (int @untagged@)
--  = "pcre_namecount_stub_bc" "pcre_namecount_stub"
--
--external nameentrysize : regexp -> (int @untagged@)
--  = "pcre_nameentrysize_stub_bc" "pcre_nameentrysize_stub"
--
--external names : regexp -> string array = "pcre_names_stub"
--external firstbyte : regexp -> firstbyte_info = "pcre_firstbyte_stub"
--external firsttable : regexp -> string option = "pcre_firsttable_stub"
--external lastliteral : regexp -> char option = "pcre_lastliteral_stub"
--external study_stat : regexp -> study_stat = "pcre_study_stat_stub" @noalloc@
--
--
--(* Compilation of patterns *)
--
--type chtables
--
--external maketables : unit -> chtables = "pcre_maketables_stub"
--
--(*  Internal use only! *)
--external pcre_study : regexp -> unit = "pcre_study_stub"
--
--external compile : (icflag  @untagged@) -> chtables option -> string -> regexp
--  = "pcre_compile_stub_bc" "pcre_compile_stub"
--
--external get_match_limit : regexp -> int option = "pcre_get_match_limit_stub"
--
--external get_match_limit_recursion : regexp -> int option
--  = "pcre_get_match_limit_recursion_stub"
--
--(* Internal use only! *)
--external set_imp_match_limit : regexp -> (int @untagged@) -> regexp
--  = "pcre_set_imp_match_limit_stub_bc" "pcre_set_imp_match_limit_stub"
--  @noalloc@
--
--(* Internal use only! *)
--external set_imp_match_limit_recursion : regexp -> (int @untagged@) -> regexp
--  =
--  "pcre_set_imp_match_limit_recursion_stub_bc"
--  "pcre_set_imp_match_limit_recursion_stub"
--  @noalloc@
--
--let regexp
--      ?(study = true) ?limit ?limit_recursion
--      ?(iflags = 0) ?flags ?chtables pat =
--  let rex =
--    match flags with
--    | Some flag_list -> compile (cflags flag_list) chtables pat
--    | _ -> compile iflags chtables pat
--  in
--  if study then pcre_study rex;
--  let rex =
--    match limit with
--    | None -> rex
--    | Some lim -> set_imp_match_limit rex lim
--  in
--  match limit_recursion with
--  | None -> rex
--  | Some lim -> set_imp_match_limit_recursion rex lim
--
--let regexp_or
--      ?study ?limit ?limit_recursion ?(iflags = 0) ?flags ?chtables pats =
--  let check pat =
--    try ignore (regexp ~study:false ~iflags ?flags ?chtables pat)
--    with Error error -> raise (Regexp_or (pat, error))
--  in
--  List.iter check pats;
--  let big_pat =
--    let cnv pat = "(?:" ^ pat ^ ")" in
--    String.concat "|" (List.rev (List.rev_map cnv pats))
--  in
--  regexp ?study ?limit ?limit_recursion ~iflags ?flags ?chtables big_pat
--
--let bytes_unsafe_blit_string str str_ofs bts bts_ofs len =
--  let str_bts = Bytes.unsafe_of_string str in
--  Bytes.unsafe_blit str_bts str_ofs bts bts_ofs len
--
--let string_unsafe_sub str ofs len =
--  let res = Bytes.create len in
--  bytes_unsafe_blit_string str ofs res 0 len;
--  Bytes.unsafe_to_string res
--
--let quote s =
--  let len = String.length s in
--  let buf = Bytes.create (len lsl 1) in
--  let pos = ref 0 in
--  for i = 0 to len - 1 do
--    match String.unsafe_get s i with
--    | '\\' | '^' | '$' | '.' | '[' | '|'
--    | '('  | ')' | '?' | '*' | '+' | '{' as c ->
--      Bytes.unsafe_set buf !pos '\\';
--      incr pos;
--      Bytes.unsafe_set buf !pos c;
--      incr pos
--    | c -> Bytes.unsafe_set buf !pos c; incr pos
--  done;
--  string_unsafe_sub (Bytes.unsafe_to_string buf) 0 !pos
--
--
--(* Matching of patterns and subpattern extraction *)
--
--(* Default regular expression when none is provided by the user *)
--let def_rex = regexp "\\s+"
--
--type substrings = string * int array
--
--type callout_data =
--  {
--    callout_number : int;
--    substrings : substrings;
--    start_match : int;
--    current_position : int;
--    capture_top : int;
--    capture_last : int;
--    pattern_position : int;
--    next_item_length : int;
--  }
--
--type callout = callout_data -> unit
--
--let get_subject (subj, _) = subj
--
--let num_of_subs (_, ovector) = Array.length ovector / 3
--
--let get_offset_start ovector str_num =
--  if str_num < 0 || str_num >= Array.length ovector / 3 then
--    invalid_arg "Pcre.get_offset_start: illegal offset";
--  let offset = str_num lsl 1 in
--  offset, Array.unsafe_get ovector offset
--
--let get_substring_aux (subj, ovector) offset start =
--  if start < 0 then raise Not_found
--  else
--    string_unsafe_sub subj start (Array.unsafe_get ovector (offset + 1) - start)
--
--let get_substring (_, ovector as substrings) str_num =
--  let offset, start = get_offset_start ovector str_num in
--  get_substring_aux substrings offset start
--
--let get_substring_ofs (_subj, ovector) str_num =
--  let offset, start = get_offset_start ovector str_num in
--  if start < 0 then raise Not_found
--  else start, Array.unsafe_get ovector (offset + 1)
--
--let unsafe_get_substring (_, ovector as substrings) str_num =
--  let offset = str_num lsl 1 in
--  try get_substring_aux substrings offset (Array.unsafe_get ovector offset)
--  with Not_found -> ""
--
--let get_substrings ?(full_match = true) (_, ovector as substrings) =
--  if full_match then
--    Array.init (Array.length ovector / 3) (unsafe_get_substring substrings)
--  else
--    let len = (Array.length ovector / 3) - 1 in
--    Array.init len (fun n -> unsafe_get_substring substrings (n + 1))
--
--let unsafe_get_opt_substring (_, ovector as substrings) str_num =
--  let offset = str_num lsl 1 in
--  try
--    let start = Array.unsafe_get ovector offset in
--    let str = get_substring_aux substrings offset start in
--    Some str
--  with Not_found -> None
--
--let get_opt_substrings ?(full_match = true) (_, ovector as substrings) =
--  if full_match then
--    Array.init (Array.length ovector / 3) (unsafe_get_opt_substring substrings)
--  else
--    let len = (Array.length ovector / 3) - 1 in
--    Array.init len (fun n -> unsafe_get_opt_substring substrings (n + 1))
--
--external get_stringnumber : regexp -> string -> (int @untagged@)
--  = "pcre_get_stringnumber_stub_bc" "pcre_get_stringnumber_stub"
--
--let get_named_substring rex name substrings =
--  get_substring substrings (get_stringnumber rex name)
--
--let get_named_substring_ofs rex name substrings =
--  get_substring_ofs substrings (get_stringnumber rex name)
--
--external unsafe_pcre_exec :
--  (irflag @untagged@) ->
--  regexp ->
--  pos : (int @untagged@) ->
--  subj_start : (int @untagged@) ->
--  subj : string ->
--  int array ->
--  callout option ->
--  unit = "pcre_exec_stub_bc" "pcre_exec_stub"
--
--let make_ovector rex =
--  let subgroups1 = capturecount rex + 1 in
--  let subgroups2 = subgroups1 lsl 1 in
--  subgroups2, Array.make (subgroups1 + subgroups2) 0
--
--let pcre_exec ?(iflags = 0) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
--              ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let _, ovector = make_ovector rex in
--  unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
--  ovector
--
--let exec ?iflags ?flags ?rex ?pat ?pos ?callout subj =
--  subj, pcre_exec ?iflags ?flags ?rex ?pat ?pos ?callout subj
--
--let next_match ?iflags ?flags ?rex ?pat ?(pos = 0) ?callout (subj, ovector) =
--  let pos = Array.unsafe_get ovector 1 + pos in
--  let subj_len = String.length subj in
--  if pos < 0 || pos > subj_len then
--    invalid_arg "Pcre.next_match: illegal offset";
--  subj, pcre_exec ?iflags ?flags ?rex ?pat ~pos ?callout subj
--
--let rec copy_lst ar n = function
--  | [] -> ar
--  | h :: t -> Array.unsafe_set ar n h; copy_lst ar (n - 1) t
--
--let exec_all ?(iflags = 0) ?flags ?(rex = def_rex) ?pat ?pos ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let (_, ovector as sstrs) = exec ~iflags ~rex ?pos ?callout subj in
--  let null_flags = iflags lor 0x0400 in
--  let subj_len = String.length subj in
--  let rec loop pos (subj, ovector as sstrs) n lst =
--    let maybe_ovector =
--      try
--        let first = Array.unsafe_get ovector 0 in
--        if first = pos && Array.unsafe_get ovector 1 = pos then
--          if pos = subj_len then None
--          else Some (pcre_exec ~iflags:null_flags ~rex ~pos ?callout subj)
--        else Some (pcre_exec ~iflags ~rex ~pos ?callout subj)
--      with Not_found -> None in
--    match maybe_ovector with
--    | Some ovector ->
--        let new_pos = Array.unsafe_get ovector 1 in
--        loop new_pos (subj, ovector) (n + 1) (sstrs :: lst)
--    | None -> copy_lst (Array.make (n + 1) sstrs) (n - 1) lst in
--  loop (Array.unsafe_get ovector 1) sstrs 0 []
--
--let extract ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
--  get_substrings ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
--
--let extract_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
--  get_opt_substrings
--    ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
--
--let extract_all ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
--  let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
--  Array.map (get_substrings ?full_match) many_sstrs
--
--let extract_all_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
--  let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
--  Array.map (get_opt_substrings ?full_match) many_sstrs
--
--let pmatch ?iflags ?flags ?rex ?pat ?pos ?callout subj =
--  try ignore (pcre_exec ?iflags ?flags ?rex ?pat ?pos ?callout subj); true
--  with Not_found -> false
--
--
--(* String substitution *)
--
--(* Elements of a substitution pattern *)
--type subst =
--  | SubstString of int * int (* Denotes a substring in the substitution *)
--  | Backref of int           (* nth backreference ($0 is program name!) *)
--  | Match                    (* The whole matched string *)
--  | PreMatch                 (* The string before the match *)
--  | PostMatch                (* The string after the match *)
--  | LastParenMatch           (* The last matched group *)
--
--(* Information on substitution patterns *)
--type substitution = string     (* The substitution string *)
--                  * int        (* Highest group number of backreferences *)
--                  * bool       (* Makes use of "LastParenMatch" *)
--                  * subst list (* The list of substitution elements *)
--
--(* Only used internally in "subst" *)
--exception FoundAt of int
--
--let zero = Char.code '0'
--
--let subst str =
--  let max_br = ref 0 in
--  let with_lp = ref false in
--  let lix = String.length str - 1 in
--  let rec loop acc n =
--    if lix < n then acc
--    else
--      try
--        for i = n to lix do
--          if String.unsafe_get str i = '$' then raise (FoundAt i)
--        done;
--        SubstString (n, lix - n + 1) :: acc
--      with FoundAt i ->
--        if i = lix then SubstString (n, lix - n + 1) :: acc
--        else
--          let i1 = i + 1 in
--          let acc = if n = i then acc else SubstString (n, i - n) :: acc in
--          match String.unsafe_get str i1 with
--          | '0'..'9' as c ->
--              let subpat_nr = ref (Char.code c - zero) in
--              (try
--                for j = i1 + 1 to lix do
--                  let c = String.unsafe_get str j in
--                  if c >= '0' && c <= '9' then
--                    subpat_nr := 10 * !subpat_nr + Char.code c - zero
--                  else raise (FoundAt j)
--                done;
--                max_br := max !subpat_nr !max_br;
--                Backref !subpat_nr :: acc
--              with FoundAt j ->
--                max_br := max !subpat_nr !max_br;
--                loop (Backref !subpat_nr :: acc) j)
--          | '!'  -> loop acc (i1 + 1)
--          | '$'  -> loop (SubstString (i1, 1) :: acc) (i1 + 1)
--          | '&'  -> loop (Match :: acc) (i1 + 1)
--          | '`'  -> loop (PreMatch :: acc) (i1 + 1)
--          | '\'' -> loop (PostMatch :: acc) (i1 + 1)
--          | '+'  ->
--              with_lp := true;
--              loop (LastParenMatch :: acc) (i1 + 1)
--          | _    -> loop acc i1 in
--  let subst_lst = loop [] 0 in
--  str, !max_br, !with_lp, subst_lst
--
--let def_subst = subst ""
--
--(* Calculates a list of tuples (str, offset, len) which contain
--   substrings to be copied on substitutions. Internal use only! *)
--let calc_trans_lst subgroups2 ovector subj templ subst_lst =
--  let prefix_len = Array.unsafe_get ovector 0 in
--  let last = Array.unsafe_get ovector 1 in
--  let coll (res_len, trans_lst as accu) =
--    let return_lst (_str, _ix, len as el) =
--      if len = 0 then accu else res_len + len, el :: trans_lst in
--    function
--    | SubstString (ix, len) -> return_lst (templ, ix, len)
--    | Backref 0 ->
--        let prog_name = Sys.argv.(0) in
--        return_lst (prog_name, 0, String.length prog_name)
--    | Backref n ->
--        let offset = n lsl 1 in
--        let start = Array.unsafe_get ovector offset in
--        let len = Array.unsafe_get ovector (offset + 1) - start in
--        return_lst (subj, start, len)
--    | Match -> return_lst (subj, prefix_len, last - prefix_len)
--    | PreMatch -> return_lst (subj, 0, prefix_len)
--    | PostMatch -> return_lst (subj, last, String.length subj - last)
--    | LastParenMatch ->
--        let subgroups2_2 = subgroups2 - 2 in
--        let pos = ref subgroups2_2 in
--        let ix = ref (Array.unsafe_get ovector subgroups2_2) in
--        while !ix < 0 do
--          let pos_2 = !pos - 2 in
--          pos := pos_2;
--          ix := Array.unsafe_get ovector pos_2
--        done;
--        return_lst (subj, !ix, Array.unsafe_get ovector (!pos + 1) - !ix) in
--  List.fold_left coll (0, []) subst_lst
--
--let replace ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
--            ?(pos = 0) ?(itempl = def_subst) ?templ ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let templ, max_br, with_lp, subst_lst =
--    match templ with
--    | Some str -> subst str
--    | _ -> itempl in
--  let subj_len = String.length subj in
--  if pos < 0 || pos > subj_len then invalid_arg "Pcre.replace: illegal offset";
--  let subgroups2, ovector = make_ovector rex in
--  let nsubs = (subgroups2 lsr 1) - 1 in
--  if max_br > nsubs then
--    failwith "Pcre.replace: backreference denotes nonexistent subpattern";
--  if with_lp && nsubs = 0 then failwith "Pcre.replace: no backreferences";
--  let rec loop full_len trans_lsts cur_pos =
--    if
--      cur_pos > subj_len ||
--      try
--        unsafe_pcre_exec
--          iflags rex ~pos:cur_pos ~subj_start:0 ~subj
--          ovector callout;
--        false
--      with Not_found -> true
--    then
--      let postfix_len = max (subj_len - cur_pos) 0 in
--      let left = pos + full_len in
--      let res = Bytes.create (left + postfix_len) in
--      bytes_unsafe_blit_string subj 0 res 0 pos;
--      bytes_unsafe_blit_string subj cur_pos res left postfix_len;
--      let inner_coll ofs (templ, ix, len) =
--        bytes_unsafe_blit_string templ ix res ofs len; ofs + len in
--      let coll ofs (res_len, trans_lst) =
--        let new_ofs = ofs - res_len in
--        let _ = List.fold_left inner_coll new_ofs trans_lst in
--        new_ofs in
--      let _ = List.fold_left coll left trans_lsts in
--      Bytes.unsafe_to_string res
--    else
--      let first = Array.unsafe_get ovector 0 in
--      let len = first - cur_pos in
--      let res_len, _ as trans_lst_el =
--        calc_trans_lst subgroups2 ovector subj templ subst_lst in
--      let trans_lsts =
--        if len > 0 then
--          trans_lst_el :: (len, [(subj, cur_pos, len)]) :: trans_lsts
--        else trans_lst_el :: trans_lsts in
--      let full_len = full_len + len + res_len in
--      let next = first + 1 in
--      let last = Array.unsafe_get ovector 1 in
--      if last < next then
--        if first < subj_len then
--          let new_trans_lsts = (1, [(subj, cur_pos + len, 1)]) :: trans_lsts in
--          loop (full_len + 1) new_trans_lsts next
--        else loop full_len trans_lsts next
--      else loop full_len trans_lsts last in
--  loop 0 [] pos
--
--let qreplace ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
--             ?(pos = 0) ?(templ = "") ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let subj_len = String.length subj in
--  if pos < 0 || pos > subj_len then invalid_arg "Pcre.qreplace: illegal offset";
--  let templ_len = String.length templ in
--  let _, ovector = make_ovector rex in
--  let rec loop full_len subst_lst cur_pos =
--    if
--      cur_pos > subj_len ||
--      try
--        unsafe_pcre_exec
--          iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector callout;
--        false
--      with Not_found -> true
--    then
--      let postfix_len = max (subj_len - cur_pos) 0 in
--      let left = pos + full_len in
--      let res = Bytes.create (left + postfix_len) in
--      bytes_unsafe_blit_string subj 0 res 0 pos;
--      bytes_unsafe_blit_string subj cur_pos res left postfix_len;
--      let coll ofs = function
--        | Some (substr, ix, len) ->
--            let new_ofs = ofs - len in
--            bytes_unsafe_blit_string substr ix res new_ofs len;
--            new_ofs
--        | None ->
--            let new_ofs = ofs - templ_len in
--            bytes_unsafe_blit_string templ 0 res new_ofs templ_len;
--            new_ofs in
--      let _ = List.fold_left coll left subst_lst in
--      Bytes.unsafe_to_string res
--    else
--      let first = Array.unsafe_get ovector 0 in
--      let len = first - cur_pos in
--      let subst_lst =
--        if len > 0 then None :: Some (subj, cur_pos, len) :: subst_lst
--        else None :: subst_lst in
--      let last = Array.unsafe_get ovector 1 in
--      let full_len = full_len + len + templ_len in
--      let next = first + 1 in
--      if last < next then
--        if first < subj_len then
--          loop (full_len + 1) (Some (subj, cur_pos + len, 1) :: subst_lst) next
--        else loop full_len subst_lst next
--      else loop full_len subst_lst last in
--  loop 0 [] pos
--
--let substitute_substrings ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
--                          ?(pos = 0) ?callout ~subst subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let subj_len = String.length subj in
--  if pos < 0 || pos > subj_len then invalid_arg "Pcre.substitute: illegal offset";
--  let _, ovector = make_ovector rex in
--  let rec loop full_len subst_lst cur_pos =
--    if
--      cur_pos > subj_len ||
--      try
--        unsafe_pcre_exec
--          iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector callout;
--        false
--      with Not_found -> true
--    then
--      let postfix_len = max (subj_len - cur_pos) 0 in
--      let left = pos + full_len in
--      let res = Bytes.create (left + postfix_len) in
--      bytes_unsafe_blit_string subj 0 res 0 pos;
--      bytes_unsafe_blit_string subj cur_pos res left postfix_len;
--      let coll ofs (templ, ix, len) =
--        let new_ofs = ofs - len in
--        bytes_unsafe_blit_string templ ix res new_ofs len;
--        new_ofs in
--      let _ = List.fold_left coll left subst_lst in
--      Bytes.unsafe_to_string res
--    else
--      let first = Array.unsafe_get ovector 0 in
--      let len = first - cur_pos in
--      let templ = subst (subj, ovector) in
--      let templ_len = String.length templ in
--      let subst_lst =
--        if len > 0 then
--          (templ, 0, templ_len) :: (subj, cur_pos, len) :: subst_lst
--        else (templ, 0, templ_len) :: subst_lst in
--      let last = Array.unsafe_get ovector 1 in
--      let full_len = full_len + len + templ_len in
--      let next = first + 1 in
--      if last < next then
--        if first < subj_len then
--          loop (full_len + 1) ((subj, cur_pos + len, 1) :: subst_lst) next
--        else loop full_len subst_lst next
--      else loop full_len subst_lst last in
--  loop 0 [] pos
--
--let substitute ?iflags ?flags ?rex ?pat ?pos ?callout ~subst:str_subst subj =
--  let subst (subj, ovector) =
--    let first = Array.unsafe_get ovector 0 in
--    let last = Array.unsafe_get ovector 1 in
--    str_subst (string_unsafe_sub subj first (last - first)) in
--  substitute_substrings ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
--
--let replace_first ?(iflags = 0) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
--                  ?(itempl = def_subst) ?templ ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let templ, max_br, with_lp, subst_lst =
--    match templ with
--    | Some str -> subst str
--    | _ -> itempl in
--  let subgroups2, ovector = make_ovector rex in
--  let nsubs = (subgroups2 lsr 1) - 1 in
--  if max_br > nsubs then
--    failwith "Pcre.replace_first: backreference denotes nonexistent subpattern";
--  if with_lp && nsubs = 0 then failwith "Pcre.replace_first: no backreferences";
--  try
--    unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
--    let res_len, trans_lst =
--      calc_trans_lst subgroups2 ovector subj templ subst_lst in
--    let first = Array.unsafe_get ovector 0 in
--    let last = Array.unsafe_get ovector 1 in
--    let rest = String.length subj - last in
--    let res = Bytes.create (first + res_len + rest) in
--    bytes_unsafe_blit_string subj 0 res 0 first;
--    let coll ofs (templ, ix, len) =
--      bytes_unsafe_blit_string templ ix res ofs len; ofs + len in
--    let ofs = List.fold_left coll first trans_lst in
--    bytes_unsafe_blit_string subj last res ofs rest;
--    Bytes.unsafe_to_string res
--  with Not_found -> subj
--
--let qreplace_first ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
--                   ?(pos = 0) ?(templ = "") ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let _, ovector = make_ovector rex in
--  try
--    unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
--    let first = Array.unsafe_get ovector 0 in
--    let last = Array.unsafe_get ovector 1 in
--    let len = String.length templ in
--    let rest = String.length subj - last in
--    let postfix_start = first + len in
--    let res = Bytes.create (postfix_start + rest) in
--    bytes_unsafe_blit_string subj 0 res 0 first;
--    bytes_unsafe_blit_string templ 0 res first len;
--    bytes_unsafe_blit_string subj last res postfix_start rest;
--    Bytes.unsafe_to_string res
--  with Not_found -> subj
--
--let substitute_substrings_first ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
--                                ?(pos = 0) ?callout ~subst subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let _, ovector = make_ovector rex in
--  try
--    unsafe_pcre_exec iflags rex ~pos ~subj_start:0 ~subj ovector callout;
--    let subj_len = String.length subj in
--    let prefix_len = Array.unsafe_get ovector 0 in
--    let last = Array.unsafe_get ovector 1 in
--    let templ = subst (subj, ovector) in
--    let postfix_len = subj_len - last in
--    let templ_len = String.length templ in
--    let postfix_start = prefix_len + templ_len in
--    let res = Bytes.create (postfix_start + postfix_len) in
--    bytes_unsafe_blit_string subj 0 res 0 prefix_len;
--    bytes_unsafe_blit_string templ 0 res prefix_len templ_len;
--    bytes_unsafe_blit_string subj last res postfix_start postfix_len;
--    Bytes.unsafe_to_string res
--  with Not_found -> subj
--
--let substitute_first ?iflags ?flags ?rex ?pat ?pos
--                     ?callout ~subst:str_subst subj =
--  let subst (subj, ovector) =
--    let first = Array.unsafe_get ovector 0 in
--    let last = Array.unsafe_get ovector 1 in
--    str_subst (string_unsafe_sub subj first (last - first)) in
--  substitute_substrings_first
--    ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
--
--
--(* Splitting *)
--
--let internal_psplit flags rex max pos callout subj =
--  let subj_len = String.length subj in
--  if subj_len = 0 then []
--  else if max = 1 then [subj]
--  else
--    let subgroups2, ovector = make_ovector rex in
--
--    (* Adds contents of subgroups to the string accumulator *)
--    let handle_subgroups strs =
--      let strs = ref strs in
--      let i = ref 2 in
--      while !i < subgroups2 do
--        let first = Array.unsafe_get ovector !i in
--        incr i;
--        let last = Array.unsafe_get ovector !i in
--        let str =
--          if first < 0 then ""
--          else string_unsafe_sub subj first (last - first) in
--        strs := str :: !strs; incr i
--      done;
--      !strs in
--
--    (* Performs the recursive split *)
--    let rec loop strs cnt pos prematch =
--      let len = subj_len - pos in
--      if len < 0 then strs
--      else
--        (* Checks termination due to max restriction *)
--        if cnt = 0 then
--          if prematch &&
--            try
--              unsafe_pcre_exec
--                flags rex ~pos ~subj_start:pos ~subj ovector callout;
--              true
--            with Not_found -> false
--          then
--            let last = Array.unsafe_get ovector 1 in
--            let strs = handle_subgroups strs in
--            string_unsafe_sub subj last (subj_len - last) :: strs
--          else string_unsafe_sub subj pos len :: strs
--
--        (* Calculates next accumulator state for splitting *)
--        else
--          if
--            try
--              unsafe_pcre_exec
--                flags rex ~pos ~subj_start:pos ~subj ovector callout;
--              false
--            with Not_found -> true
--          then string_unsafe_sub subj pos len :: strs
--          else
--            let first = Array.unsafe_get ovector 0 in
--            let last = Array.unsafe_get ovector 1 in
--            if first = pos then
--              if last = pos then
--                let strs = if prematch then handle_subgroups strs else strs in
--                if len = 0 then "" :: strs
--                else if
--                  try
--                    unsafe_pcre_exec
--                      (flags lor 0x0410) rex ~pos ~subj_start:pos ~subj
--                      ovector callout;
--                    true
--                  with Not_found -> false
--                then
--                  let new_strs = handle_subgroups ("" :: strs) in
--                  loop new_strs (cnt - 1) (Array.unsafe_get ovector 1) false
--                else
--                  let new_strs = string_unsafe_sub subj pos 1 :: strs in
--                  loop new_strs (cnt - 1) (pos + 1) true
--              else
--                if prematch then loop (handle_subgroups strs) cnt last false
--                else loop (handle_subgroups ("" :: strs)) (cnt - 1) last false
--            else
--              let new_strs = string_unsafe_sub subj pos (first - pos) :: strs in
--              loop (handle_subgroups new_strs) (cnt - 1) last false in
--    loop [] (max - 1) pos false
--
--let rec strip_all_empty = function "" :: t -> strip_all_empty t | l -> l
--
--external isspace : char -> bool = "pcre_isspace_stub" @noalloc@
--
--let rec find_no_space ix len str =
--  if ix = len || not (isspace (String.unsafe_get str ix)) then ix
--  else find_no_space (ix + 1) len str
--
--let split ?(iflags = 0) ?flags ?rex ?pat ?(pos = 0) ?(max = 0) ?callout subj =
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let res =
--    match pat, rex with
--    | Some str, _ -> internal_psplit iflags (regexp str) max pos callout subj
--    | _, Some rex -> internal_psplit iflags rex max pos callout subj
--    | _ ->
--        (* special case for Perl-splitting semantics *)
--        let len = String.length subj in
--        if pos > len || pos < 0 then failwith "Pcre.split: illegal offset";
--        let new_pos = find_no_space pos len subj in
--        internal_psplit iflags def_rex max new_pos callout subj in
--  List.rev (if max = 0 then strip_all_empty res else res)
--
--let asplit ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj =
--  Array.of_list (split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj)
--
--
--(* Full splitting *)
--
--type split_result = Text of string
--                  | Delim of string
--                  | Group of int * string
--                  | NoGroup
--
--let rec strip_all_empty_full = function
--  | Delim _ :: rest -> strip_all_empty_full rest
--  | l -> l
--
--let full_split ?(iflags = 0) ?flags ?(rex = def_rex) ?pat
--               ?(pos = 0) ?(max = 0) ?callout subj =
--  let rex = match pat with Some str -> regexp str | _ -> rex in
--  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
--  let subj_len = String.length subj in
--  if subj_len = 0 then []
--  else if max = 1 then [Text (subj)]
--  else
--    let subgroups2, ovector = make_ovector rex in
--
--    (* Adds contents of subgroups to the string accumulator *)
--    let handle_subgroups strs =
--      let strs = ref strs in
--      let i = ref 2 in
--      while !i < subgroups2 do
--        let group_nr = !i lsr 1 in
--        let first = Array.unsafe_get ovector !i in
--        incr i;
--        let last = Array.unsafe_get ovector !i in
--        let str =
--          if first < 0 then NoGroup
--          else
--            let group_str = string_unsafe_sub subj first (last - first) in
--            Group (group_nr, group_str) in
--        strs := str :: !strs; incr i
--      done;
--      !strs in
--
--    (* Performs the recursive split *)
--    let rec loop strs cnt pos prematch =
--      let len = subj_len - pos in
--      if len < 0 then strs
--      else
--        (* Checks termination due to max restriction *)
--        if cnt = 0 then
--          if prematch &&
--            try
--              unsafe_pcre_exec
--                iflags rex ~pos ~subj_start:pos ~subj ovector callout;
--               true
--            with Not_found -> false
--          then
--            let first = Array.unsafe_get ovector 0 in
--            let last = Array.unsafe_get ovector 1 in
--            let delim = Delim (string_unsafe_sub subj first (last - first)) in
--            Text (string_unsafe_sub subj last (subj_len - last))
--              :: handle_subgroups (delim :: strs)
--          else
--            if len = 0 then strs
--            else Text (string_unsafe_sub subj pos len) :: strs
--
--        (* Calculates next accumulator state for splitting *)
--        else
--          if
--            try
--              unsafe_pcre_exec
--                iflags rex ~pos ~subj_start:pos ~subj ovector callout;
--              false
--            with Not_found -> true
--          then
--            if len = 0 then strs
--            else Text (string_unsafe_sub subj pos len) :: strs
--          else
--            let first = Array.unsafe_get ovector 0 in
--            let last = Array.unsafe_get ovector 1 in
--            if first = pos then
--              if last = pos then
--                if len = 0 then handle_subgroups (Delim "" :: strs)
--                else
--                  let empty_groups = handle_subgroups [] in
--                  if
--                    try
--                      unsafe_pcre_exec
--                        (iflags lor 0x0410) rex ~pos ~subj_start:pos ~subj
--                        ovector callout;
--                      true
--                    with Not_found -> false
--                  then
--                    let first = Array.unsafe_get ovector 0 in
--                    let last = Array.unsafe_get ovector 1 in
--                    let delim =
--                      Delim (string_unsafe_sub subj first (last - first)) in
--                    let new_strs =
--                      handle_subgroups (
--                        delim :: (if prematch then strs
--                                  else empty_groups @ (Delim "" :: strs))) in
--                    loop new_strs (cnt - 1) last false
--                  else
--                    let new_strs =
--                      Text (string_unsafe_sub subj pos 1)
--                        :: empty_groups @ Delim "" :: strs in
--                    loop new_strs (cnt - 1) (pos + 1) true
--              else
--                  let delim =
--                    Delim (string_unsafe_sub subj first (last - first)) in
--                  loop (handle_subgroups (delim :: strs)) cnt last false
--            else
--              let delim = Delim (string_unsafe_sub subj first (last - first)) in
--              let pre_strs =
--                Text (string_unsafe_sub subj pos (first - pos)) :: strs in
--              loop
--                (handle_subgroups (delim :: pre_strs)) (cnt - 1) last false in
--    let res = loop [] (max - 1) pos true in
--    List.rev (if max = 0 then strip_all_empty_full res else res)
--
--
--(* Additional convenience functions useful in combination with this library *)
--
--let foreach_line ?(ic = stdin) f =
--  try while true do f (input_line ic) done with End_of_file -> ()
--
--let foreach_file filenames f =
--  let do_with_file filename =
--    let file = open_in filename in
--    try f filename file; close_in file
--    with exn -> close_in file; raise exn in
--  List.iter do_with_file filenames
-diff --git a/bundles/pcre/pcre-ocaml/src/pcre.mli b/bundles/pcre/pcre-ocaml/src/pcre.mli
-deleted file mode 100644
-index 5047bb865..000000000
---- a/bundles/pcre/pcre-ocaml/src/pcre.mli
-+++ /dev/null
-@@ -1,930 +0,0 @@
--(*
--   PCRE-OCAML - Perl Compatibility Regular Expressions for OCaml
--
--   Copyright (C) 1999-  Markus Mottl
--   email: markus.mottl@gmail.com
--   WWW:   http://www.ocaml.info
--
--   This library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
--
--   This library 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
--   Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public
--   License along with this library; if not, write to the Free Software
--   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--*)
--
--(** Perl Compatibility Regular Expressions for OCaml
--
--    {e %%VERSION%% - {{:%%PKG_HOMEPAGE%%}homepage}}
--*)
--
--
--(** {6 Exceptions} *)
--
--type error =
--  | Partial  (** String only matched the pattern partially *)
--  | BadPartial  (** Pattern contains items that cannot be used together
--                    with partial matching. *)
--  | BadPattern of string * int  (** [BadPattern (msg, pos)] regular
--                                    expression is malformed.  The reason
--                                    is in [msg], the position of the
--                                    error in the pattern in [pos]. *)
--  | BadUTF8  (** UTF8 string being matched is invalid *)
--  | BadUTF8Offset  (** Gets raised when a UTF8 string being matched with
--                       offset is invalid. *)
--  | MatchLimit  (** Maximum allowed number of match attempts with
--                    backtracking or recursion is reached during matching.
--                    ALL FUNCTIONS CALLING THE MATCHING ENGINE MAY RAISE
--                    IT!!! *)
--  | RecursionLimit
--  | InternalError of string
--      (** [InternalError msg] C-library exhibits unknown/undefined
--          behaviour.  The reason is in [msg]. *)
--
--(** Exception indicating PCRE errors. *)
--exception Error of error
--
--(** [Backtrack] used in callout functions to force backtracking. *)
--exception Backtrack
--
--(** [Regexp_or (pat, error)] gets raised for sub-pattern [pat] by [regexp_or]
--    if it failed to compile. *)
--exception Regexp_or of string * error
--
--(** {6 Compilation and runtime flags and their conversion functions} *)
--
--(** Internal representation of compilation flags *)
--type icflag
--
--(** Internal representation of runtime flags *)
--and  irflag
--
--(** Compilation flags *)
--and cflag =
--  [ `CASELESS        (** Case insensitive matching *)
--  | `MULTILINE       (** '^' and '$' match before/after newlines,
--                         not just at the beginning/end of a string *)
--  | `DOTALL          (** '.' matches all characters (newlines, too) *)
--  | `EXTENDED        (** Ignores whitespace and PERL-comments. Behaves
--                         like the '/x'-option in PERL *)
--  | `ANCHORED        (** Pattern matches only at start of string *)
--  | `DOLLAR_ENDONLY  (** '$' in pattern matches only at end of string *)
--  | `EXTRA           (** Reserved for future extensions of PCRE *)
--  | `UNGREEDY        (** Quantifiers not greedy anymore, only
--                         if followed by '?' *)
--  | `UTF8            (** Treats patterns and strings as UTF8 characters. *)
--  | `NO_UTF8_CHECK   (** Turns off validity checks on UTF8 strings for
--                         efficiency reasons. WARNING: invalid UTF8
--                         strings may cause a crash then! *)
--  | `NO_AUTO_CAPTURE (** Disables the use of numbered capturing parentheses *)
--  | `AUTO_CALLOUT    (** Automatically inserts callouts with id 255
--                         before each pattern item *)
--  | `FIRSTLINE       (** Unanchored patterns must match before/at first NL *)
--  ]
--
--val cflags : cflag list -> icflag
--(** [cflags cflag_list] converts a list of compilation flags to
--    their internal representation. *)
--
--val cflag_list : icflag -> cflag list
--(** [cflag_list cflags] converts internal representation of
--    compilation flags to a list. *)
--
--(** Runtime flags *)
--type rflag =
--  [ `ANCHORED  (** Treats pattern as if it were anchored *)
--  | `NOTBOL    (** Beginning of string is not treated as beginning of line *)
--  | `NOTEOL    (** End of string is not treated as end of line *)
--  | `NOTEMPTY  (** Empty strings are not considered to be a valid match *)
--  | `PARTIAL   (** Turns on partial matching *)
--  ]
--
--val rflags : rflag list -> irflag
--(** [rflags rflag_list] converts a list of runtime flags to
--    their internal representation. *)
--
--val rflag_list : irflag -> rflag list
--(** [rflag_list rflags] converts internal representation of
--    runtime flags to a list. *)
--
--
--(** {6 Information on the PCRE-configuration (build-time options)} *)
--
--(** Version information *)
--val version : string  (** Version of the PCRE-C-library *)
--
--(** Indicates whether UTF8-support is enabled *)
--val config_utf8 : bool
--
--(** Character used as newline *)
--val config_newline : char
--
--(** Number of bytes used for internal linkage of regular expressions *)
--val config_link_size : int
--
--(** Default limit for calls to internal matching function *)
--val config_match_limit : int
--
--(** Default limit recursion for calls to internal matching function *)
--val config_match_limit_recursion : int
--
--(** Indicates use of stack recursion in matching function *)
--val config_stackrecurse : bool
--
--
--(** {6 Information on patterns} *)
--
--(** Information on matching of "first chars" in patterns *)
--type firstbyte_info =
--  [ `Char of char  (** Fixed first character *)
--  | `Start_only    (** Pattern matches at beginning and end of newlines *)
--  | `ANCHORED      (** Pattern is anchored *)
--  ]
--
--(** Information on the study status of patterns *)
--type study_stat =
--  [ `Not_studied (** Pattern has not yet been studied *)
--  | `Studied     (** Pattern has been studied successfully *)
--  | `Optimal     (** Pattern could not be improved by studying *)
--  ]
--
--type regexp (** Compiled regular expressions *)
--
--(** [options regexp] @return compilation flags of [regexp]. *)
--val options : regexp -> icflag
--
--(** [size regexp] @return memory size of [regexp]. *)
--val size : regexp -> int
--
--(** [studysize regexp] @return memory size of study information of [regexp]. *)
--val studysize : regexp -> int
--
--(** [capturecount regexp] @return number of capturing subpatterns in
--    [regexp]. *)
--val capturecount : regexp -> int
--
--(** [backrefmax regexp] @return number of highest backreference in [regexp]. *)
--val backrefmax : regexp -> int
--
--(** [namecount regexp] @return number of named subpatterns in [regexp]. *)
--val namecount : regexp -> int
--
--(** [nameentrysize regexp] @return size of longest name of named
--    subpatterns in [regexp] + 3. *)
--val nameentrysize : regexp -> int
--
--(** [names regex] @return array of names of named substrings in [regexp]. *)
--val names : regexp -> string array
--
--(** [firstbyte regexp] @return firstbyte info on [regexp]. *)
--val firstbyte : regexp -> firstbyte_info
--
--(** [firsttable regexp] @return some 256-bit (32-byte) fixed set table in
--    form of a string for [regexp] if available, [None] otherwise. *)
--val firsttable : regexp -> string option
--
--(** [lastliteral regexp] @return some last matching character of [regexp]
--    if available, [None] otherwise. *)
--val lastliteral : regexp -> char option
--
--(** [study_stat regexp] @return study status of [regexp]. *)
--val study_stat : regexp -> study_stat
--
--val get_stringnumber : regexp -> string -> int
--(** [get_stringnumber rex name] @return the index of the named substring
--    [name] in regular expression [rex]. This index can then be used with
--    [get_substring].
--
--    @raise Invalid_arg if there is no such named substring. *)
--
--val get_match_limit : regexp -> int option
--(** [get_match_limit rex] @return some match limit of regular expression
--    [rex] or [None]. *)
--
--val get_match_limit_recursion : regexp -> int option
--(** [get_match_limit_recursion rex] @return some recursion match limit
--    of regular expression [rex] or [None]. *)
--
--
--(** {6 Compilation of patterns} *)
--
--type chtables (** Alternative set of char tables for pattern matching *)
--
--val maketables : unit -> chtables
--(** Generates new set of char tables for the current locale. *)
--
--val regexp :
--  ?study : bool ->
--  ?limit : int ->
--  ?limit_recursion : int ->
--  ?iflags : icflag ->
--  ?flags : cflag list ->
--  ?chtables : chtables ->
--  string -> regexp
--(** [regexp ?study ?limit ?limit_recursion ?iflags ?flags ?chtables pattern]
--    compiles [pattern] with [flags] when given, with [iflags] otherwise, and
--    with char tables [chtables]. If [study] is true, then the resulting regular
--    expression will be studied. If [limit] is specified, this sets a limit to
--    the amount of recursion and backtracking (only lower than the builtin
--    default!). If this limit is exceeded, [MatchLimit] will be raised during
--    matching.
--
--    @param study default = true
--    @param limit default = no extra limit other than default
--    @param limit_recursion default = no extra limit_recursion other than default
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param chtables default = builtin char tables
--
--    @return the regular expression.
--
--    For detailed documentation on how you can specify PERL-style regular
--    expressions (= patterns), please consult the PCRE-documentation
--    ("man pcrepattern") or PERL-manuals.
--    @see <http://www.perl.com> www.perl.com *)
--
--val regexp_or :
--  ?study : bool ->
--  ?limit : int ->
--  ?limit_recursion : int ->
--  ?iflags : icflag ->
--  ?flags : cflag list ->
--  ?chtables : chtables ->
--  string list -> regexp
--(** [regexp_or ?study ?limit ?limit_recursion ?iflags ?flags ?chtables patterns]
--    like {!regexp}, but combines [patterns] as alternatives (or-patterns) into
--    one regular expression. *)
--
--val quote : string -> string
--(** [quote str] @return the quoted string of [str]. *)
--
--
--(** {6 Subpattern extraction} *)
--
--type substrings (** Information on substrings after pattern matching *)
--
--val get_subject : substrings -> string
--(** [get_subject substrings] @return the subject string of [substrings]. *)
--
--val num_of_subs : substrings -> int
--(** [num_of_subs substrings] @return number of strings in [substrings]
--    (whole match inclusive). *)
--
--val get_substring : substrings -> int -> string
--(** [get_substring substrings n] @return the [n]th substring
--    (0 is whole match) of [substrings].
--
--    @raise Invalid_argument if [n] is not in the range of the number of
--    substrings.
--    @raise Not_found if the corresponding subpattern did not capture
--           a substring. *)
--
--val get_substring_ofs : substrings -> int -> int * int
--(** [get_substring_ofs substrings n] @return the offset tuple of the
--    [n]th substring of [substrings] (0 is whole match).
--
--    @raise Invalid_argument if [n] is not in the range of the number
--           of substrings.
--    @raise Not_found if the corresponding subpattern did not capture
--           a substring. *)
--
--val get_substrings :
--  ?full_match : bool ->
--  substrings -> string array
--(** [get_substrings ?full_match substrings] @return the array of
--    substrings in [substrings]. It includes the full match at index 0
--    when [full_match] is [true], the captured substrings only when it
--    is [false]. If a subpattern did not capture a substring, the empty
--    string is returned in the corresponding position instead.
--
--    @param full_match default = true *)
--
--val get_opt_substrings :
--  ?full_match : bool ->
--  substrings -> string option array
--(** [get_opt_substrings ?full_match substrings] @return the array of
--    optional substrings in [substrings]. It includes [Some full_match_str]
--    at index 0 when [full_match] is [true], [Some captured_substrings]
--    only when it is [false]. If a subpattern did not capture a substring,
--    [None] is returned in the corresponding position instead.
--
--    @param full_match default = true *)
--
--val get_named_substring : regexp -> string -> substrings -> string
--(** [get_named_substring rex name substrings] @return the named substring
--    [name] in regular expression [rex] and [substrings].
--
--    @raise Invalid_argument if there is no such named substring.
--    @raise Not_found if the corresponding subpattern did not capture
--           a substring. *)
--
--val get_named_substring_ofs : regexp -> string -> substrings -> int * int
--(** [get_named_substring_ofs rex name substrings] @return the offset
--    tuple of the named substring [name] in regular expression [rex] and
--    [substrings].
--
--    @raise Invalid_argument if there is no such named substring.
--    @raise Not_found if the corresponding subpattern did not capture
--           a substring. *)
--
--
--(** {6 Callouts} *)
--
--type callout_data =
--  {
--    callout_number : int; (** Callout number *)
--    substrings : substrings; (** Substrings matched so far *)
--    start_match : int;  (** Subject start offset of current match attempt *)
--    current_position : int;  (** Subject offset of current match pointer *)
--    capture_top : int;  (** Number of the highest captured substring so far *)
--    capture_last : int;  (** Number of the most recently captured substring *)
--    pattern_position : int;  (** Offset of next match item in pattern string *)
--    next_item_length : int;  (** Length of next match item in pattern string *)
--  }
--
--(** Type of callout functions *)
--type callout = callout_data -> unit
--(** Callouts are referred to in patterns as "(?Cn)" where "n" is a
--    [callout_number] ranging from 0 to 255.  Substrings captured so far
--    are accessible as usual via [substrings].  You will have to consider
--    [capture_top] and [capture_last] to know about the current state of
--    valid substrings.
--
--    By raising exception [Backtrack] within a callout function, the user
--    can force the pattern matching engine to backtrack to other possible
--    solutions.  Other exceptions will terminate matching immediately
--    and return control to OCaml.
--*)
--
--
--(** {6 Matching of patterns and subpattern extraction} *)
--
--val pcre_exec :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  string -> int array
--(** [pcre_exec ?iflags ?flags ?rex ?pat ?pos ?callout subj] @return an
--    array of offsets that describe the position of matched subpatterns in
--    the string [subj] starting at position [pos] with pattern [pat] when
--    given, regular expression [rex] otherwise. The array also contains
--    additional workspace needed by the match engine. Uses [flags] when
--    given, the precompiled [iflags] otherwise. Callouts are handled by
--    [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val exec :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  string -> substrings
--(** [exec ?iflags ?flags ?rex ?pat ?pos ?callout subj] @return substring
--    information on string [subj] starting at position [pos] with pattern
--    [pat] when given, regular expression [rex] otherwise. Uses [flags]
--    when given, the precompiled [iflags] otherwise. Callouts are handled
--    by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val exec_all :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  string -> substrings array
--(** [exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj] @return
--    an array of substring information of all matching substrings in
--    string [subj] starting at position [pos] with pattern [pat] when
--    given, regular expression [rex] otherwise. Uses [flags] when given,
--    the precompiled [iflags] otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val next_match :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  substrings -> substrings
--(** [next_match ?iflags ?flags ?rex ?pat ?pos ?callout substrs] @return
--    substring information on the match that follows on the last
--    match denoted by [substrs], jumping over [pos] characters (also
--    backwards!), using pattern [pat] when given, regular expression
--    [rex] otherwise. Uses [flags] when given, the precompiled [iflags]
--    otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match.
--    @raise Invalid_arg if [pos] let matching start outside of
--           the subject string. *)
--
--val extract :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?full_match : bool ->
--  ?callout : callout ->
--  string -> string array
--(** [extract ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
--    @return the array of substrings that match [subj] starting at
--    position [pos], using pattern [pat] when given, regular expression
--    [rex] otherwise. Uses [flags] when given, the precompiled [iflags]
--    otherwise. It includes the full match at index 0 when [full_match] is
--    [true], the captured substrings only when it is [false]. Callouts are
--    handled by [callout].  If a subpattern did not capture a substring,
--    the empty string is returned in the corresponding position instead.
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param full_match default = true
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val extract_opt :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?full_match : bool ->
--  ?callout : callout ->
--  string -> string option array
--(** [extract_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
--    @return the array of optional substrings that match [subj] starting
--    at position [pos], using pattern [pat] when given, regular expression
--    [rex] otherwise. Uses [flags] when given, the precompiled [iflags]
--    otherwise. It includes [Some full_match_str] at index 0 when
--    [full_match] is [true], [Some captured-substrings] only when it is
--    [false]. Callouts are handled by [callout].  If a subpattern did
--    not capture a substring, [None] is returned in the corresponding
--    position instead.
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param full_match default = true
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val extract_all :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?full_match : bool ->
--  ?callout : callout ->
--  string -> string array array
--(** [extract_all ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
--    @return an array of arrays of all matching substrings that match
--    [subj] starting at position [pos], using pattern [pat] when given,
--    regular expression [rex] otherwise. Uses [flags] when given, the
--    precompiled [iflags] otherwise. It includes the full match at index
--    0 of the extracted string arrays when [full_match] is [true], the
--    captured substrings only when it is [false]. Callouts are handled by
--    [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param full_match default = true
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val extract_all_opt :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?full_match : bool ->
--  ?callout : callout ->
--  string -> string option array array
--(** [extract_all_opt
--      ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
--    @return an array of arrays of all optional matching substrings that
--    match [subj] starting at position [pos], using pattern [pat] when
--    given, regular expression [rex] otherwise. Uses [flags] when given,
--    the precompiled [iflags] otherwise. It includes [Some full_match_str]
--    at index 0 of the extracted string arrays when [full_match] is [true],
--    [Some captured_substrings] only when it is [false]. Callouts are
--    handled by [callout].  If a subpattern did not capture a substring,
--    [None] is returned in the corresponding position instead.
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param full_match default = true
--    @param callout default = ignore callouts
--
--    @raise Not_found if pattern does not match. *)
--
--val pmatch :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  string -> bool
--(** [pmatch ?iflags ?flags ?rex ?pat ?pos ?callout subj] @return [true]
--    if [subj] is matched by pattern [pat] when given, regular expression
--    [rex] otherwise, starting at position [pos]. Uses [flags] when given,
--    the precompiled [iflags] otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts *)
--
--
--(** {6 String substitution} *)
--
--(** Information on substitution patterns *)
--type substitution
--
--val subst : string -> substitution
--(** [subst str] converts the string [str] representing a
--    substitution pattern to the internal representation
--
--    The contents of the substitution string [str] can be normal text
--    mixed with any of the following (mostly as in PERL):
--
--    - {e $\[0-9\]+}  - a "$" immediately followed by an arbitrary number.
--                       "$0" stands for the name of the executable,
--                       any other number for the n-th backreference.
--    - {e $&}         - the whole matched pattern
--    - {e $`}         - the text before the match
--    - {e $'}         - the text after the match
--    - {e $+}         - the last group that matched
--    - {e $$}         - a single "$"
--    - {e $!}         - delimiter which does not appear in the substitution.
--                       Can be used to part "$[0-9]+" from an immediately
--                       following other number. *)
--
--val replace :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?itempl : substitution ->
--  ?templ : string ->
--  ?callout : callout ->
--  string -> string
--(** [replace ?iflags ?flags ?rex ?pat ?pos ?itempl ?templ ?callout subj]
--    replaces all substrings of [subj] matching pattern [pat] when given,
--    regular expression [rex] otherwise, starting at position [pos] with
--    the substitution string [templ] when given, [itempl] otherwise. Uses
--    [flags] when given, the precompiled [iflags] otherwise. Callouts
--    are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param itempl default = empty string
--    @param templ default = ignored
--    @param callout default = ignore callouts
--
--    @raise Failure if there are backreferences to nonexistent subpatterns. *)
--
--val qreplace :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?templ : string ->
--  ?callout : callout ->
--  string -> string
--(** [qreplace ?iflags ?flags ?rex ?pat ?pos ?templ ?callout subj]
--    replaces all substrings of [subj] matching pattern [pat] when given,
--    regular expression [rex] otherwise, starting at position [pos]
--    with the string [templ]. Uses [flags] when given, the precompiled
--    [iflags] otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param templ default = ignored
--    @param callout default = ignore callouts *)
--
--val substitute_substrings :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  subst : (substrings -> string) ->
--  string -> string
--(** [substitute_substrings ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj]
--    replaces all substrings of [subj] matching pattern [pat] when given,
--    regular expression [rex] otherwise, starting at position [pos]
--    with the result of function [subst] applied to the substrings
--    of the match. Uses [flags] when given, the precompiled [iflags]
--    otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts *)
--
--val substitute :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  subst : (string -> string) ->
--  string -> string
--(** [substitute ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj]
--    replaces all substrings of [subj] matching pattern [pat] when given,
--    regular expression [rex] otherwise, starting at position [pos] with
--    the result of function [subst] applied to the match. Uses [flags]
--    when given, the precompiled [iflags] otherwise. Callouts are handled
--    by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts *)
--
--val replace_first :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?itempl : substitution ->
--  ?templ : string ->
--  ?callout : callout ->
--  string -> string
--(** [replace_first ?iflags ?flags ?rex ?pat ?pos ?itempl ?templ ?callout subj]
--    replaces the first substring of [subj] matching pattern [pat] when
--    given, regular expression [rex] otherwise, starting at position
--    [pos] with the substitution string [templ] when given, [itempl]
--    otherwise. Uses [flags] when given, the precompiled [iflags]
--    otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param itempl default = empty string
--    @param templ default = ignored
--    @param callout default = ignore callouts
--
--    @raise Failure if there are backreferences to nonexistent subpatterns. *)
--
--val qreplace_first :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?templ : string ->
--  ?callout : callout ->
--  string -> string
--(** [qreplace_first ?iflags ?flags ?rex ?pat ?pos ?templ ?callout subj]
--    replaces the first substring of [subj] matching pattern [pat] when
--    given, regular expression [rex] otherwise, starting at position [pos]
--    with the string [templ]. Uses [flags] when given, the precompiled
--    [iflags] otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param templ default = ignored
--    @param callout default = ignore callouts *)
--
--val substitute_substrings_first :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  subst : (substrings -> string) ->
--  string -> string
--(** [substitute_substrings_first
--       ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj]
--    replaces the first substring of [subj] matching pattern [pat] when
--    given, regular expression [rex] otherwise, starting at position
--    [pos] with the result of function [subst] applied to the substrings
--    of the match. Uses [flags] when given, the precompiled [iflags]
--    otherwise. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts *)
--
--val substitute_first :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?callout : callout ->
--  subst : (string -> string) ->
--  string -> string
--(** [substitute_first ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj]
--    replaces the first substring of [subj] matching pattern [pat] when
--    given, regular expression [rex] otherwise, starting at position
--    [pos] with the result of function [subst] applied to the match. Uses
--    [flags] when given, the precompiled [iflags] otherwise. Callouts
--    are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param callout default = ignore callouts *)
--
--
--(** {6 Splitting} *)
--
--val split :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?max : int ->
--  ?callout : callout ->
--  string -> string list
--(** [split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj] splits [subj]
--    into a list of at most [max] strings, using as delimiter pattern
--    [pat] when given, regular expression [rex] otherwise, starting at
--    position [pos]. Uses [flags] when given, the precompiled [iflags]
--    otherwise. If [max] is zero, trailing empty fields are stripped. If
--    it is negative, it is treated as arbitrarily large. If neither [pat]
--    nor [rex] are specified, leading whitespace will be stripped! Should
--    behave exactly as in PERL. Callouts are handled by [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param max default = 0
--    @param callout default = ignore callouts *)
--
--val asplit :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?max : int ->
--  ?callout : callout ->
--  string -> string array
--(** [asplit ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj] same as
--    {!Pcre.split} but @return an array instead of a list. *)
--
--(** Result of a {!Pcre.full_split} *)
--type split_result = Text of string        (** Text part of split string *)
--                  | Delim of string       (** Delimiter part of split string *)
--                  | Group of int * string (** Subgroup of matched delimiter
--                                              (subgroup_nr, subgroup_str) *)
--                  | NoGroup               (** Unmatched subgroup *)
--
--val full_split :
--  ?iflags : irflag ->
--  ?flags : rflag list ->
--  ?rex : regexp ->
--  ?pat : string ->
--  ?pos : int ->
--  ?max : int ->
--  ?callout : callout ->
--  string -> split_result list
--(** [full_split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj] splits
--    [subj] into a list of at most [max] elements of type "split_result",
--    using as delimiter pattern [pat] when given, regular expression
--    [rex] otherwise, starting at position [pos]. Uses [flags] when given,
--    the precompiled [iflags] otherwise. If [max] is zero, trailing empty
--    fields are stripped. If it is negative, it is treated as arbitrarily
--    large. Should behave exactly as in PERL. Callouts are handled by
--    [callout].
--
--    @param iflags default = no extra flags
--    @param flags default = ignored
--    @param rex default = matches whitespace
--    @param pat default = ignored
--    @param pos default = 0
--    @param max default = 0
--    @param callout default = ignore callouts *)
--
--
--(** {6 Additional convenience functions} *)
--
--val foreach_line :
--  ?ic : in_channel ->
--  (string -> unit) -> unit
--(** [foreach_line ?ic f] applies [f] to each line in inchannel [ic] until
--    the end-of-file is reached.
--
--    @param ic default = stdin *)
--
--val foreach_file : string list -> (string -> in_channel -> unit) -> unit
--(** [foreach_file filenames f] opens each file in the list [filenames]
--    for input and applies [f] to each filename and the corresponding
--    channel. Channels are closed after each operation (even when
--    exceptions occur - they get reraised afterwards!). *)
--
--
--(** {6 {b UNSAFE STUFF - USE WITH CAUTION!}} *)
--
--val unsafe_pcre_exec :
--  irflag ->
--  regexp ->
--  pos : int ->
--  subj_start : int ->
--  subj : string ->
--  int array ->
--  callout option ->
--  unit
--(** [unsafe_pcre_exec flags rex ~pos ~subj_start ~subj offset_vector].
--    You should read the C-source to know what happens.
--    If you do not understand it - {b don't use this function!} *)
--
--val make_ovector : regexp -> int * int array
--(** [make_ovector regexp] calculates the tuple (subgroups2, ovector)
--    which is the number of subgroup offsets and the offset array. *)
-diff --git a/bundles/pcre/pcre-ocaml/src/pcre_stubs.c.in b/bundles/pcre/pcre-ocaml/src/pcre_stubs.c.in
-deleted file mode 100644
-index 66dfb7b0d..000000000
---- a/bundles/pcre/pcre-ocaml/src/pcre_stubs.c.in
-+++ /dev/null
-@@ -1,862 +0,0 @@
--/*
--   PCRE-OCAML - Perl Compatibility Regular Expressions for OCaml
--
--   Copyright (C) 1999-  Markus Mottl
--   email: markus.mottl@gmail.com
--   WWW:   http://www.ocaml.info
--
--   This library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
--
--   This library 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
--   Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public
--   License along with this library; if not, write to the Free Software
--   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--*/
--
--#if defined(_WIN32)
--#  define snprintf _snprintf
--#  if defined(_DLL)
--#    define PCREextern __declspec(dllexport)
--#  else
--#    define PCREextern
--#  endif
--#endif
--
--#if _WIN64
--  typedef long long *ovec_dst_ptr;
--#else
--  typedef long *ovec_dst_ptr;
--#endif
--
--#if __GNUC__ >= 3
--# define inline inline __attribute__ ((always_inline))
--# define __unused __attribute__ ((unused))
--#else
--# define __unused
--# define inline
--#endif
--
--#include <ctype.h>
--#include <string.h>
--#include <stdio.h>
--
--#include <caml/mlvalues.h>
--#include <caml/alloc.h>
--#include <caml/memory.h>
--#include <caml/fail.h>
--#include <caml/callback.h>
--#include <caml/custom.h>
--
--#include <pcre.h>
--
--/* Error codes as defined for pcre 7.9, undefined in pcre 4.5 */
--#ifndef PCRE_ERROR_PARTIAL
--#define PCRE_ERROR_PARTIAL        (-12)
--#endif
--#ifndef PCRE_ERROR_BADPARTIAL
--#define PCRE_ERROR_BADPARTIAL     (-13)
--#endif
--#ifndef PCRE_ERROR_RECURSIONLIMIT
--#define PCRE_ERROR_RECURSIONLIMIT (-21)
--#endif
--
--typedef const unsigned char *chartables;  /* Type of chartable sets */
--
--/* Contents of callout data */
--struct cod {
--  long subj_start;        /* Start of subject string */
--  value *v_substrings_p;  /* Pointer to substrings matched so far */
--  value *v_cof_p;         /* Pointer to callout function */
--  value v_exn;            /* Possible exception raised by callout function */
--};
--
--/* Cache for exceptions */
--static value *pcre_exc_Error         = NULL;  /* Exception [Error] */
--static value *pcre_exc_Backtrack     = NULL;  /* Exception [Backtrack] */
--
--/* Cache for polymorphic variants */
--static value var_Start_only;   /* Variant [`Start_only] */
--static value var_ANCHORED;     /* Variant [`ANCHORED] */
--static value var_Char;         /* Variant [`Char char] */
--static value var_Not_studied;  /* Variant [`Not_studied] */
--static value var_Studied;      /* Variant [`Studied] */
--static value var_Optimal;      /* Variant [`Optimal] */
--
--static value None = Val_int(0);
--
--/* Data associated with OCaml values of PCRE regular expression */
--struct pcre_ocaml_regexp { pcre *rex; pcre_extra *extra; int studied; };
--
--#define Pcre_ocaml_regexp_val(v) \
--  ((struct pcre_ocaml_regexp *) Data_custom_val(v))
--
--#define get_rex(v) Pcre_ocaml_regexp_val(v)->rex
--#define get_extra(v) Pcre_ocaml_regexp_val(v)->extra
--#define get_studied(v) Pcre_ocaml_regexp_val(v)->studied
--
--#define set_rex(v, r) Pcre_ocaml_regexp_val(v)->rex = r
--#define set_extra(v, e) Pcre_ocaml_regexp_val(v)->extra = e
--#define set_studied(v, s) Pcre_ocaml_regexp_val(v)->studied = s
--
--/* Data associated with OCaml values of PCRE tables */
--struct pcre_ocaml_tables { chartables tables; };
--
--#define Pcre_ocaml_tables_val(v) \
--  ((struct pcre_ocaml_tables *) Data_custom_val(v))
--
--#define get_tables(v) Pcre_ocaml_tables_val(v)->tables
--#define set_tables(v, t) Pcre_ocaml_tables_val(v)->tables = t
--
--/* Converts subject offsets from C-integers to OCaml-Integers.
--
--   This is a bit tricky, because there are 32- and 64-bit platforms around
--   and OCaml chooses the larger possibility for representing integers when
--   available (also in arrays) - not so the PCRE!
--*/
--static inline void copy_ovector(
--  long subj_start, const int *ovec_src, ovec_dst_ptr ovec_dst, int subgroups2)
--{
--  if (subj_start == 0)
--    while (subgroups2--) {
--      *ovec_dst = Val_int(*ovec_src);
--      --ovec_src; --ovec_dst;
--    }
--  else
--    while (subgroups2--) {
--      *ovec_dst = Val_long(*ovec_src + subj_start);
--      --ovec_src; --ovec_dst;
--    }
--}
--
--/* Callout handler */
--static int pcre_callout_handler(pcre_callout_block* cb)
--{
--  struct cod *cod = (struct cod *) cb->callout_data;
--
--  if (cod != NULL) {
--    /* Callout is available */
--    value v_res;
--
--    /* Set up parameter array */
--    value v_callout_data = caml_alloc_small(8, 0);
--
--    const value v_substrings = *cod->v_substrings_p;
--
--    const int capture_top = cb->capture_top;
--    int subgroups2 = capture_top << 1;
--    const int subgroups2_1 = subgroups2 - 1;
--
--    const int *ovec_src = cb->offset_vector + subgroups2_1;
--    ovec_dst_ptr ovec_dst = &Field(Field(v_substrings, 1), 0) + subgroups2_1;
--    long subj_start = cod->subj_start;
--
--    copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
--
--    Field(v_callout_data, 0) = Val_int(cb->callout_number);
--    Field(v_callout_data, 1) = v_substrings;
--    Field(v_callout_data, 2) = Val_int(cb->start_match + subj_start);
--    Field(v_callout_data, 3) = Val_int(cb->current_position + subj_start);
--    Field(v_callout_data, 4) = Val_int(capture_top);
--    Field(v_callout_data, 5) = Val_int(cb->capture_last);
--    Field(v_callout_data, 6) = Val_int(cb->pattern_position);
--    Field(v_callout_data, 7) = Val_int(cb->next_item_length);
--
--    /* Perform callout */
--    v_res = caml_callback_exn(*cod->v_cof_p, v_callout_data);
--
--    if (Is_exception_result(v_res)) {
--      /* Callout raised an exception */
--      const value v_exn = Extract_exception(v_res);
--      if (Field(v_exn, 0) == *pcre_exc_Backtrack) return 1;
--      cod->v_exn = v_exn;
--      return PCRE_ERROR_CALLOUT;
--    }
--  }
--
--  return 0;
--}
--
--/* Fetchs the named OCaml-values + caches them and
--   calculates + caches the variant hash values */
--CAMLprim value pcre_ocaml_init(value __unused v_unit)
--{
--  pcre_exc_Error     = caml_named_value("Pcre.Error");
--  pcre_exc_Backtrack = caml_named_value("Pcre.Backtrack");
--
--  var_Start_only  = caml_hash_variant("Start_only");
--  var_ANCHORED    = caml_hash_variant("ANCHORED");
--  var_Char        = caml_hash_variant("Char");
--  var_Not_studied = caml_hash_variant("Not_studied");
--  var_Studied     = caml_hash_variant("Studied");
--  var_Optimal     = caml_hash_variant("Optimal");
--
--  pcre_callout = &pcre_callout_handler;
--
--  return Val_unit;
--}
--
--/* Finalizing deallocation function for chartable sets */
--static void pcre_dealloc_tables(value v_tables)
--{ (pcre_free)((void *) get_tables(v_tables)); }
--
--/* Finalizing deallocation function for compiled regular expressions */
--static void pcre_dealloc_regexp(value v_rex)
--{
--  void *extra = get_extra(v_rex);
--  if (extra != NULL)
--#ifdef PCRE_STUDY_JIT_COMPILE
--    pcre_free_study(extra);
--#else
--    pcre_free(extra);
--#endif
--  (pcre_free)(get_rex(v_rex));
--}
--
--
--/* Raising exceptions */
--
--@CAMLnoreturn_start@
--static inline void raise_pcre_error(value v_arg)
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_partial()
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_bad_partial()
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_bad_utf8()
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_bad_utf8_offset()
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_match_limit()
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_recursion_limit()
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_bad_pattern(const char *msg, int pos)
--@CAMLnoreturn_end@;
--
--@CAMLnoreturn_start@
--static inline void raise_internal_error(char *msg)
--@CAMLnoreturn_end@;
--
--static inline void raise_pcre_error(value v_arg)
--{ caml_raise_with_arg(*pcre_exc_Error, v_arg); }
--
--static inline void raise_partial() { raise_pcre_error(Val_int(0)); }
--static inline void raise_bad_partial() { raise_pcre_error(Val_int(1)); }
--static inline void raise_bad_utf8() { raise_pcre_error(Val_int(2)); }
--static inline void raise_bad_utf8_offset() { raise_pcre_error(Val_int(3)); }
--static inline void raise_match_limit() { raise_pcre_error(Val_int(4)); }
--static inline void raise_recursion_limit() { raise_pcre_error(Val_int(5)); }
--
--static inline void raise_bad_pattern(const char *msg, int pos)
--{
--  CAMLparam0();
--  CAMLlocal1(v_msg);
--  value v_arg;
--  v_msg = caml_copy_string(msg);
--  v_arg = caml_alloc_small(2, 0);
--  Field(v_arg, 0) = v_msg;
--  Field(v_arg, 1) = Val_int(pos);
--  raise_pcre_error(v_arg);
--  CAMLnoreturn;
--}
--
--static inline void raise_internal_error(char *msg)
--{
--  CAMLparam0();
--  CAMLlocal1(v_msg);
--  value v_arg;
--  v_msg = caml_copy_string(msg);
--  v_arg = caml_alloc_small(1, 1);
--  Field(v_arg, 0) = v_msg;
--  raise_pcre_error(v_arg);
--  CAMLnoreturn;
--}
--
--/* PCRE pattern compilation */
--
--static struct custom_operations regexp_ops = {
--  "pcre_ocaml_regexp",
--  pcre_dealloc_regexp,
--  custom_compare_default,
--  custom_hash_default,
--  custom_serialize_default,
--  custom_deserialize_default,
--  custom_compare_ext_default
--};
--
--/* Makes compiled regular expression from compilation options, an optional
--   value of chartables and the pattern string */
--
--CAMLprim value pcre_compile_stub(@intnat@ v_opt, value v_tables, value v_pat)
--{
--  value v_rex;  /* Final result -> value of type [regexp] */
--  const char *error = NULL;  /* pointer to possible error message */
--  int error_ofs = 0;  /* offset in the pattern at which error occurred */
--
--  /* If v_tables = [None], then pointer to tables is NULL, otherwise
--     set it to the appropriate value */
--  chartables tables =
--    (v_tables == None) ? NULL : get_tables(Field(v_tables, 0));
--
--  /* Compiles the pattern */
--  pcre *regexp = pcre_compile(String_val(v_pat), @Int_val@(v_opt), &error,
--                              &error_ofs, tables);
--
--  /* Raises appropriate exception with [BadPattern] if the pattern
--     could not be compiled */
--  if (regexp == NULL) raise_bad_pattern(error, error_ofs);
--
--  /* GC will do a full cycle every 1_000_000 regexp allocations (a typical
--     regexp probably consumes less than 100 bytes -> maximum of 100_000_000
--     bytes unreclaimed regexps) */
--  v_rex =
--    caml_alloc_custom(&regexp_ops,
--        sizeof(struct pcre_ocaml_regexp), 1, 1000000);
--
--  set_rex(v_rex, regexp);
--  set_extra(v_rex, NULL);
--  set_studied(v_rex, 0);
--
--  return v_rex;
--}
--
--CAMLprim value pcre_compile_stub_bc(value v_opt, value v_tables, value v_pat)
--{
--  return pcre_compile_stub(@Int_val_val@(v_opt), v_tables, v_pat);
--}
--
--
--/* Studies a regexp */
--CAMLprim value pcre_study_stub(value v_rex)
--{
--  /* If it has not yet been studied */
--  if (! get_studied(v_rex)) {
--    const char *error = NULL;
--    pcre_extra *extra = pcre_study(get_rex(v_rex), 0, &error);
--    if (error != NULL) caml_invalid_argument((char *) error);
--    set_extra(v_rex, extra);
--    set_studied(v_rex, 1);
--  }
--  return v_rex;
--}
--
--
--/* Gets the match limit recursion of a regular expression if it exists */
--CAMLprim value pcre_get_match_limit_recursion_stub(value v_rex)
--{
--  pcre_extra *extra = get_extra(v_rex);
--  if (extra == NULL) return None;
--  if (extra->flags & PCRE_EXTRA_MATCH_LIMIT_RECURSION) {
--    value v_lim = Val_int(extra->match_limit_recursion);
--    value v_res = caml_alloc_small(1, 0);
--    Field(v_res, 0) = v_lim;
--    return v_res;
--  }
--  return None;
--}
--
--/* Gets the match limit of a regular expression if it exists */
--CAMLprim value pcre_get_match_limit_stub(value v_rex)
--{
--  pcre_extra *extra = get_extra(v_rex);
--  if (extra == NULL) return None;
--  if (extra->flags & PCRE_EXTRA_MATCH_LIMIT) {
--    value v_lim = Val_int(extra->match_limit);
--    value v_res = caml_alloc_small(1, 0);
--    Field(v_res, 0) = v_lim;
--    return v_res;
--  }
--  return None;
--}
--
--
--/* Sets a match limit for a regular expression imperatively */
--
--CAMLprim value pcre_set_imp_match_limit_stub(value v_rex, @intnat@ v_lim)
--{
--  pcre_extra *extra = get_extra(v_rex);
--  if (extra == NULL) {
--    extra = pcre_malloc(sizeof(pcre_extra));
--    extra->flags = PCRE_EXTRA_MATCH_LIMIT;
--    set_extra(v_rex, extra);
--  } else {
--    unsigned long *flags_ptr = &extra->flags;
--    *flags_ptr = PCRE_EXTRA_MATCH_LIMIT | *flags_ptr;
--  }
--  extra->match_limit = @Int_val@(v_lim);
--  return v_rex;
--}
--
--CAMLprim value pcre_set_imp_match_limit_stub_bc(value v_rex, value v_lim)
--{
--  return pcre_set_imp_match_limit_stub(v_rex, @Int_val_val@(v_lim));
--}
--
--
--/* Sets a match limit recursion for a regular expression imperatively */
--
--CAMLprim value pcre_set_imp_match_limit_recursion_stub(
--    value v_rex, @intnat@ v_lim)
--{
--  pcre_extra *extra = get_extra(v_rex);
--  if (extra == NULL) {
--    extra = pcre_malloc(sizeof(pcre_extra));
--    extra->flags = PCRE_EXTRA_MATCH_LIMIT_RECURSION;
--    set_extra(v_rex, extra);
--  } else {
--    unsigned long *flags_ptr = &extra->flags;
--    *flags_ptr = PCRE_EXTRA_MATCH_LIMIT_RECURSION | *flags_ptr;
--  }
--  extra->match_limit_recursion = @Int_val@(v_lim);
--  return v_rex;
--}
--
--CAMLprim value pcre_set_imp_match_limit_recursion_stub_bc(
--    value v_rex, value v_lim)
--{
--  return pcre_set_imp_match_limit_recursion_stub(v_rex, @Int_val_val@(v_lim));
--}
--
--
--/* Performs the call to the pcre_fullinfo function */
--static inline int pcre_fullinfo_stub(value v_rex, int what, void *where)
--{
--  return pcre_fullinfo(get_rex(v_rex), get_extra(v_rex), what, where);
--}
--
--/* Some stubs for info-functions */
--
--/* Generic macro for getting integer results from pcre_fullinfo */
--#define make_intnat_info(tp, name, option) \
--  CAMLprim @intnat@ pcre_##name##_stub(value v_rex) \
--  { \
--    tp options; \
--    const int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_##option, &options); \
--    if (ret != 0) raise_internal_error("pcre_##name##_stub"); \
--    return @Val_int@(options); \
--  } \
--  \
--  CAMLprim value pcre_##name##_stub_bc(value v_rex) \
--  { return Val_int(pcre_##name##_stub(v_rex)); }
--
--make_intnat_info(unsigned long, options, OPTIONS)
--make_intnat_info(size_t, size, SIZE)
--make_intnat_info(size_t, studysize, STUDYSIZE)
--make_intnat_info(int, capturecount, CAPTURECOUNT)
--make_intnat_info(int, backrefmax, BACKREFMAX)
--make_intnat_info(int, namecount, NAMECOUNT)
--make_intnat_info(int, nameentrysize, NAMEENTRYSIZE)
--
--CAMLprim value pcre_firstbyte_stub(value v_rex)
--{
--  int firstbyte;
--  const int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_FIRSTBYTE, &firstbyte);
--
--  if (ret != 0) raise_internal_error("pcre_firstbyte_stub");
--
--  switch (firstbyte) {
--    case -1 : return var_Start_only; break;  /* [`Start_only] */
--    case -2 : return var_ANCHORED; break;    /* [`ANCHORED] */
--    default :
--      if (firstbyte < 0 )  /* Should not happen */
--        raise_internal_error("pcre_firstbyte_stub");
--      else {
--        value v_firstbyte;
--        /* Allocates the non-constant constructor [`Char of char] and fills
--           in the appropriate value */
--        v_firstbyte = caml_alloc_small(2, 0);
--        Field(v_firstbyte, 0) = var_Char;
--        Field(v_firstbyte, 1) = Val_int(firstbyte);
--        return v_firstbyte;
--      }
--  }
--}
--
--CAMLprim value pcre_firsttable_stub(value v_rex)
--{
--  const unsigned char *ftable;
--
--  int ret =
--    pcre_fullinfo_stub(v_rex, PCRE_INFO_FIRSTTABLE, (void *) &ftable);
--
--  if (ret != 0) raise_internal_error("pcre_firsttable_stub");
--
--  if (ftable == NULL) return None;
--  else {
--    value v_res, v_res_str;
--    char *ptr;
--    int i;
--
--    Begin_roots1(v_rex);
--      v_res_str = caml_alloc_string(32);
--    End_roots();
--
--    ptr = String_val(v_res_str);
--    for (i = 0; i <= 31; ++i) { *ptr = *ftable; ++ptr; ++ftable; }
--
--    Begin_roots1(v_res_str);
--      /* Allocates [Some string] from firsttable */
--      v_res = caml_alloc_small(1, 0);
--    End_roots();
--
--    Field(v_res, 0) = v_res_str;
--
--    return v_res;
--  }
--}
--
--CAMLprim value pcre_lastliteral_stub(value v_rex)
--{
--  int lastliteral;
--  const int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_LASTLITERAL,
--                                        &lastliteral);
--
--  if (ret != 0) raise_internal_error("pcre_lastliteral_stub");
--
--  if (lastliteral == -1) return None;
--  if (lastliteral < 0) raise_internal_error("pcre_lastliteral_stub");
--  else {
--    /* Allocates [Some char] */
--    value v_res = caml_alloc_small(1, 0);
--    Field(v_res, 0) = Val_int(lastliteral);
--    return v_res;
--  }
--}
--
--CAMLprim value pcre_study_stat_stub(value v_rex)
--{
--  /* Generates the appropriate constant constructor [`Optimal] or
--     [`Studied] if regexp has already been studied */
--  if (get_studied(v_rex))
--    return (get_extra(v_rex) == NULL) ? var_Optimal : var_Studied;
--
--  return var_Not_studied;  /* otherwise [`Not_studied] */
--}
--
--@CAMLnoreturn_start@
--static inline void handle_exec_error(char *loc, const int ret)
--@CAMLnoreturn_end@;
--
--static inline void handle_exec_error(char *loc, const int ret)
--{
--  switch (ret) {
--    /* Dedicated exceptions */
--    case PCRE_ERROR_NOMATCH : caml_raise_not_found();
--    case PCRE_ERROR_PARTIAL : raise_partial();
--    case PCRE_ERROR_MATCHLIMIT : raise_match_limit();
--    case PCRE_ERROR_BADPARTIAL : raise_bad_partial();
--    case PCRE_ERROR_BADUTF8 : raise_bad_utf8();
--    case PCRE_ERROR_BADUTF8_OFFSET : raise_bad_utf8_offset();
--    case PCRE_ERROR_RECURSIONLIMIT : raise_recursion_limit();
--    /* Unknown error */
--    default : {
--      char err_buf[100];
--      snprintf(err_buf, 100, "%s: unhandled PCRE error code: %d", loc, ret);
--      raise_internal_error(err_buf);
--    }
--  }
--}
--
--static inline void handle_pcre_exec_result(
--  int *ovec, value v_ovec, long ovec_len, long subj_start, int ret)
--{
--  ovec_dst_ptr ocaml_ovec = (ovec_dst_ptr) &Field(v_ovec, 0);
--  const int subgroups2 = ret * 2;
--  const int subgroups2_1 = subgroups2 - 1;
--  const int *ovec_src = ovec + subgroups2_1;
--  ovec_dst_ptr ovec_clear_stop = ocaml_ovec + (ovec_len * 2) / 3;
--  ovec_dst_ptr ovec_dst = ocaml_ovec + subgroups2_1;
--  copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
--  while (++ovec_dst < ovec_clear_stop) *ovec_dst = -1;
--}
--
--
--/* Executes a pattern match with runtime options, a regular expression, a
--   matching position, the start of the the subject string, a subject string,
--   a number of subgroup offsets, an offset vector and an optional callout
--   function */
--
--CAMLprim value pcre_exec_stub(
--    @intnat@ v_opt, value v_rex, @intnat@ v_pos, @intnat@ v_subj_start, value v_subj,
--    value v_ovec, value v_maybe_cof)
--{
--  int ret;
--  long
--    pos = @Int_val@(v_pos),
--    len = caml_string_length(v_subj),
--    subj_start = @Int_val@(v_subj_start);
--  long ovec_len = Wosize_val(v_ovec);
--
--  if (pos > len || pos < subj_start)
--    caml_invalid_argument("Pcre.pcre_exec_stub: illegal position");
--
--  if (subj_start > len || subj_start < 0)
--    caml_invalid_argument("Pcre.pcre_exec_stub: illegal subject start");
--
--  pos -= subj_start;
--  len -= subj_start;
--
--  {
--    const pcre *code = get_rex(v_rex);  /* Compiled pattern */
--    const pcre_extra *extra = get_extra(v_rex);  /* Extra info */
--    const char *ocaml_subj =
--      String_val(v_subj) + subj_start;  /* Subject string */
--    const int opt = @Int_val@(v_opt);  /* Runtime options */
--
--    /* Special case when no callout functions specified */
--    if (v_maybe_cof == None) {
--      int *ovec = (int *) &Field(v_ovec, 0);
--
--      /* Performs the match */
--      ret = pcre_exec(code, extra, ocaml_subj, len, pos, opt, ovec, ovec_len);
--
--      if (ret < 0) handle_exec_error("pcre_exec_stub", ret);
--      else handle_pcre_exec_result(ovec, v_ovec, ovec_len, subj_start, ret);
--    }
--
--    /* There are callout functions */
--    else {
--      value v_cof = Field(v_maybe_cof, 0);
--      value v_substrings;
--      char *subj = caml_stat_alloc(sizeof(char) * len);
--      int *ovec = caml_stat_alloc(sizeof(int) * ovec_len);
--      struct cod cod = { 0, (value *) NULL, (value *) NULL, (value) NULL };
--      struct pcre_extra new_extra =
--#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
--# ifdef PCRE_EXTRA_MARK
--#  ifdef PCRE_EXTRA_EXECUTABLE_JIT
--        { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL, 0, NULL, NULL };
--#  else
--        { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL, 0, NULL };
--#  endif
--# else
--        { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL, 0 };
--# endif
--#else
--        { PCRE_EXTRA_CALLOUT_DATA, NULL, 0, NULL, NULL };
--#endif
--
--      cod.subj_start = subj_start;
--      memcpy(subj, ocaml_subj, len);
--
--      Begin_roots4(v_rex, v_cof, v_substrings, v_ovec);
--        Begin_roots1(v_subj);
--          v_substrings = caml_alloc_small(2, 0);
--        End_roots();
--
--        Field(v_substrings, 0) = v_subj;
--        Field(v_substrings, 1) = v_ovec;
--
--        cod.v_substrings_p = &v_substrings;
--        cod.v_cof_p = &v_cof;
--        new_extra.callout_data = &cod;
--
--        if (extra == NULL) {
--          ret = pcre_exec(code, &new_extra, subj, len, pos, opt, ovec,
--                          ovec_len);
--        }
--        else {
--          new_extra.flags = PCRE_EXTRA_CALLOUT_DATA | extra->flags;
--          new_extra.study_data = extra->study_data;
--          new_extra.match_limit = extra->match_limit;
--          new_extra.tables = extra->tables;
--#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
--          new_extra.match_limit_recursion = extra->match_limit_recursion;
--#endif
--
--          ret = pcre_exec(code, &new_extra, subj, len, pos, opt, ovec,
--                          ovec_len);
--        }
--
--        caml_stat_free(subj);
--      End_roots();
--
--      if (ret < 0) {
--        caml_stat_free(ovec);
--        if (ret == PCRE_ERROR_CALLOUT) caml_raise(cod.v_exn);
--        else handle_exec_error("pcre_exec_stub(callout)", ret);
--      } else {
--        handle_pcre_exec_result(ovec, v_ovec, ovec_len, subj_start, ret);
--        caml_stat_free(ovec);
--      }
--    }
--  }
--
--  return Val_unit;
--}
--
--/* Byte-code hook for pcre_exec_stub
--   Needed, because there are more than 5 arguments */
--CAMLprim value pcre_exec_stub_bc(value *argv, int __unused argn)
--{
--  return
--    pcre_exec_stub(
--        @Int_val_val@(argv[0]), argv[1], @Int_val_val@(argv[2]), @Int_val_val@(argv[3]),
--        argv[4], argv[5], argv[6]);
--}
--
--static struct custom_operations tables_ops = {
--  "pcre_ocaml_tables",
--  pcre_dealloc_tables,
--  custom_compare_default,
--  custom_hash_default,
--  custom_serialize_default,
--  custom_deserialize_default,
--  custom_compare_ext_default
--};
--
--/* Generates a new set of chartables for the current locale (see man
--   page of PCRE */
--CAMLprim value pcre_maketables_stub(value __unused v_unit)
--{
--  /* GC will do a full cycle every 1_000_000 table set allocations (one
--     table set consumes 864 bytes -> maximum of 864_000_000 bytes unreclaimed
--     table sets) */
--  const value v_tables =
--    caml_alloc_custom(
--        &tables_ops, sizeof(struct pcre_ocaml_tables), 1, 1000000);
--  set_tables(v_tables, pcre_maketables());
--  return v_tables;
--}
--
--/* Wraps around the isspace-function */
--CAMLprim value pcre_isspace_stub(value v_c)
--{
--  return Val_bool(isspace(Int_val(v_c)));
--}
--
--
--/* Returns number of substring associated with a name */
--
--CAMLprim @intnat@ pcre_get_stringnumber_stub(value v_rex, value v_name)
--{
--  const int ret = pcre_get_stringnumber(get_rex(v_rex), String_val(v_name));
--  if (ret == PCRE_ERROR_NOSUBSTRING)
--    caml_invalid_argument("Named string not found");
--
--  return @Val_int@(ret);
--}
--
--CAMLprim value pcre_get_stringnumber_stub_bc(value v_rex, value v_name)
--{
--  return @Val_Val_int@(pcre_get_stringnumber_stub(v_rex, v_name));
--}
--
--
--/* Returns array of names of named substrings in a regexp */
--CAMLprim value pcre_names_stub(value v_rex)
--{
--  CAMLparam0();
--  CAMLlocal1(v_res);
--  int name_count;
--  int entry_size;
--  const char *tbl_ptr;
--  int i;
--
--  int ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_NAMECOUNT, &name_count);
--  if (ret != 0) raise_internal_error("pcre_names_stub: namecount");
--
--  ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_NAMEENTRYSIZE, &entry_size);
--  if (ret != 0) raise_internal_error("pcre_names_stub: nameentrysize");
--
--  ret = pcre_fullinfo_stub(v_rex, PCRE_INFO_NAMETABLE, &tbl_ptr);
--  if (ret != 0) raise_internal_error("pcre_names_stub: nametable");
--
--  v_res = caml_alloc(name_count, 0);
--
--  for (i = 0; i < name_count; ++i) {
--    value v_name = caml_copy_string(tbl_ptr + 2);
--    Store_field(v_res, i, v_name);
--    tbl_ptr += entry_size;
--  }
--
--  CAMLreturn(v_res);
--}
--
--/* Generic stub for getting integer results from pcre_config */
--static inline int pcre_config_int(int what)
--{
--  int ret;
--  pcre_config(what, (void *) &ret);
--  return ret;
--}
--
--/* Generic stub for getting long integer results from pcre_config */
--static inline int pcre_config_long(int what)
--{
--  long ret;
--  pcre_config(what, (void *) &ret);
--  return ret;
--}
--
--
--/* Some stubs for config-functions */
--
--/* Makes OCaml-string from PCRE-version */
--CAMLprim value pcre_version_stub(value __unused v_unit)
--{
--  return caml_copy_string((char *) pcre_version());
--}
--
--/* Returns boolean indicating UTF8-support */
--CAMLprim value pcre_config_utf8_stub(value __unused v_unit)
--{ return Val_bool(pcre_config_int(PCRE_CONFIG_UTF8)); }
--
--
--/* Returns character used as newline */
--CAMLprim value pcre_config_newline_stub(value __unused v_unit)
--{ return Val_int(pcre_config_int(PCRE_CONFIG_NEWLINE)); }
--
--
--/* Returns number of bytes used for internal linkage of regular expressions */
--
--CAMLprim @intnat@ pcre_config_link_size_stub(value __unused v_unit)
--{ return @Val_int@(pcre_config_int(PCRE_CONFIG_LINK_SIZE)); }
--
--CAMLprim value pcre_config_link_size_stub_bc(value v_unit)
--{ return @Val_Val_int@(pcre_config_link_size_stub(v_unit)); }
--
--
--/* Returns default limit for calls to internal matching function */
--
--CAMLprim @intnat@ pcre_config_match_limit_stub(value __unused v_unit)
--{ return @Val_int@(pcre_config_long(PCRE_CONFIG_MATCH_LIMIT)); }
--
--
--CAMLprim value pcre_config_match_limit_stub_bc(value v_unit)
--{ return @Val_Val_int@(pcre_config_match_limit_stub(v_unit)); }
--
--
--/* Returns default limit for recursive calls to internal matching function */
--
--CAMLprim @intnat@ pcre_config_match_limit_recursion_stub(value __unused v_unit)
--{ return @Val_int@(pcre_config_long(PCRE_CONFIG_MATCH_LIMIT_RECURSION)); }
--
--CAMLprim value pcre_config_match_limit_recursion_stub_bc(value v_unit)
--{ return @Val_Val_int@(pcre_config_match_limit_recursion_stub(v_unit)); }
--
--
--/* Returns boolean indicating use of stack recursion */
--CAMLprim value pcre_config_stackrecurse_stub(value __unused v_unit)
--{ return Val_bool(pcre_config_int(PCRE_CONFIG_STACKRECURSE)); }
-diff --git a/bundles/pcre/pcre-ocaml/.gitignore b/bundles/pcre2/pcre2-ocaml/.gitignore
-similarity index 100%
-rename from bundles/pcre/pcre-ocaml/.gitignore
-rename to bundles/pcre2/pcre2-ocaml/.gitignore
-diff --git a/bundles/pcre2/pcre2-ocaml/CHANGELOG.md b/bundles/pcre2/pcre2-ocaml/CHANGELOG.md
-new file mode 100644
-index 000000000..da11eae34
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/CHANGELOG.md
-@@ -0,0 +1,69 @@
-+# Changelog
-+
-+## [8.0.4] - 2025-10-19
-+
-+### Added
-+
-+- Provide a `make test` convenience target and generate
-+  `lib/compile_commands.json` to streamline running the suite and IDE
-+  integration.
-+- Introduce GitHub automation (Dependabot updates plus linting, formatting, and
-+  pre-commit workflows) mirroring the original `pcre-ocaml` project.
-+
-+### Changed
-+
-+- Reorganize the repository to match the upstream layout, moving library sources
-+  to `lib/`, refreshing documentation, and updating example descriptions.
-+
-+### Fixed
-+
-+- Ensure the `Pcre2.BadPattern` exception allocates short OCaml strings to avoid
-+  trailing garbage or embedded NUL bytes in error messages.
-+- Correct the offset-vector pointer cast in `pcre2_stubs.c` to remove undefined
-+  behavior when copying match offsets.
-+
-+## [8.0.3] - 2025-02-15
-+
-+### Fixed
-+
-+- Make `caml_alloc_some` static to prevent clashes with the `pcre` package when
-+  targeting OCaml 4.08-4.11.
-+
-+## [8.0.2] - 2024-12-26
-+
-+### Added
-+
-+- Restore compatibility with OCaml 4.08 through 4.11. Thanks to @nojb.
-+
-+## [8.0.1] - 2024-12-20
-+
-+### Changed
-+
-+- Merge the legacy `pcre-ocaml` changes into `pcre2-ocaml`.
-+
-+### Fixed
-+
-+- Correct `full_split` so that non-capturing groups are identified properly.
-+
-+## [7.5.3] - 2024-12-23
-+
-+### Fixed
-+
-+- Address the `full_split` regression. Thanks to @mmottl.
-+
-+## [7.5.2] - 2023-09-06
-+
-+### Added
-+
-+- Introduce the initial unit test that exercises `full_split`.
-+
-+### Fixed
-+
-+- Resolve the `full_split` bug affecting split classification.
-+
-+## [7.5.1] - 2023-09-01
-+
-+### Added
-+
-+- Create the initial `pcre2-ocaml` bindings derived from the original
-+  `pcre-ocaml` project.
-diff --git a/bundles/pcre/pcre-ocaml/LICENSE.md b/bundles/pcre2/pcre2-ocaml/LICENSE.md
-similarity index 99%
-rename from bundles/pcre/pcre-ocaml/LICENSE.md
-rename to bundles/pcre2/pcre2-ocaml/LICENSE.md
-index c35c24daa..4481e3e68 100644
---- a/bundles/pcre/pcre-ocaml/LICENSE.md
-+++ b/bundles/pcre2/pcre2-ocaml/LICENSE.md
-@@ -12,7 +12,7 @@ requirements listed in clause 6 of the GNU Lesser General Public License.
- By "a publicly distributed version of the Library", we mean either the
- unmodified Library as distributed by the authors, or a modified version
- of the Library that is distributed under the conditions defined in clause
--3 of the GNU Lesser General Public License.  This exception does not
-+2 of the GNU Lesser General Public License.  This exception does not
- however invalidate any other reasons why the executable file might be
- covered by the GNU Lesser General Public License.
- 
-@@ -24,7 +24,7 @@ Version 2.1, February 1999
- 
-     Copyright (C) 1991, 1999 Free Software Foundation, Inc.
-     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
--    
-+
-     Everyone is permitted to copy and distribute verbatim copies
-     of this license document, but changing it is not allowed.
- 
-diff --git a/bundles/pcre2/pcre2-ocaml/Makefile b/bundles/pcre2/pcre2-ocaml/Makefile
-new file mode 100644
-index 000000000..cf2ee6e51
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/Makefile
-@@ -0,0 +1,15 @@
-+.PHONY: all clean doc
-+
-+all:
-+	@dune build @install
-+	@make -C lib compile_commands.json
-+
-+test: all
-+	@dune build @install @runtest
-+
-+clean:
-+	@dune clean
-+	@make -C lib clean-compile-commands
-+
-+doc:
-+	@dune build @doc
-diff --git a/bundles/pcre2/pcre2-ocaml/README.md b/bundles/pcre2/pcre2-ocaml/README.md
-new file mode 100644
-index 000000000..a679fb4eb
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/README.md
-@@ -0,0 +1,138 @@
-+# PCRE2-OCaml - Perl Compatibility Regular Expressions for OCaml
-+
-+Fork of the original [pcre-ocaml project](https://github.com/mmottl/pcre-ocaml)
-+for PCRE2 support.
-+
-+These are the bindings as needed by the
-+[Haxe compiler](https://github.com/HaxeFoundation/haxe). I do not plan on
-+maintaining this repository.
-+
-+This [OCaml](http://www.ocaml.org) library interfaces with the C library
-+[PCRE2](http://www.pcre.org), providing Perl-compatible regular expressions for
-+string matching.
-+
-+## Features
-+
-+PCRE2-OCaml offers:
-+
-+- Pattern searching
-+- Subpattern extraction
-+- String splitting by patterns
-+- Pattern substitution
-+
-+Reasons to choose PCRE2-OCaml:
-+
-+- The PCRE2 library by Philip Hazel is mature and stable, implementing nearly
-+  all Perl regular expression features. High-level OCaml functions (split,
-+  replace, etc.) are compatible with Perl functions, as much as OCaml allows.
-+  Some developers find Perl-style regex syntax more intuitive and powerful than
-+  the Emacs-style regex used in OCaml's `Str` module.
-+
-+- PCRE2-OCaml is reentrant and thread-safe, unlike the `Str` module. This
-+  reentrancy offers convenience, eliminating concerns about library state.
-+
-+- High-level replacement and substitution functions in OCaml are faster than
-+  those in the `Str` module. When compiled to native code, they can even
-+  outperform Perl's C-based functions.
-+
-+- Returned data is unique, allowing safe destructive updates without side
-+  effects.
-+
-+- The library interface uses labels and default arguments for enhanced
-+  programming comfort.
-+
-+## Usage
-+
-+Please run:
-+
-+```sh
-+odig odoc pcre2
-+```
-+
-+Or (maybe?):
-+
-+```sh
-+dune build @doc
-+```
-+
-+Functions support two flag types:
-+
-+1. **Convenience flags**: Readable and concise, translated internally on each
-+   call. Example:
-+
-+   ```ocaml
-+   let rex = Pcre2.regexp ~flags:[`ANCHORED; `CASELESS] "some pattern" in
-+   (* ... *)
-+   ```
-+
-+   These are easy to use but may incur overhead in loops. For performance
-+   optimization, consider the next approach.
-+
-+2. **Internal flags**: Predefined and translated from convenience flags for
-+   optimal loop performance. Example:
-+
-+   ```ocaml
-+   let iflags = Pcre2.cflags [`ANCHORED; `CASELESS] in
-+   for i = 1 to 1000 do
-+     let rex = Pcre2.regexp ~iflags "some pattern constructed at runtime" in
-+     (* ... *)
-+   done
-+   ```
-+
-+   Translating flags outside loops saves cycles. Avoid creating regex in loops:
-+
-+   ```ocaml
-+   for i = 1 to 1000 do
-+     let chunks = Pcre2.split ~pat:"[ \t]+" "foo bar" in
-+     (* ... *)
-+   done
-+   ```
-+
-+   Instead, predefine the regex:
-+
-+   ```ocaml
-+   let rex = Pcre2.regexp "[ \t]+" in
-+   for i = 1 to 1000 do
-+     let chunks = Pcre2.split ~rex "foo bar" in
-+     (* ... *)
-+   done
-+   ```
-+
-+Functions use optional arguments with intuitive defaults. For instance,
-+`Pcre2.split` defaults to whitespace as the pattern. The `examples` directory
-+contains applications demonstrating PCRE2-OCaml's functionality.
-+
-+## Restartable (Partial) Pattern Matching
-+
-+PCRE2 includes a DFA match function for restarting partial matches with new
-+input, exposed via `pcre2_dfa_exec`. While not suitable for extracting
-+submatches or splitting strings, it's useful for streaming and search tasks.
-+
-+Example of a partial match restarted:
-+
-+```ocaml
-+utop # open Pcre2;;
-+utop # let rex = regexp "12+3";;
-+val rex : regexp = <abstr>
-+utop # let workspace = Array.make 40 0;;
-+val workspace : int array =
-+  [| ... |]
-+utop # pcre2_dfa_match ~rex ~flags:[`PARTIAL_SOFT] ~workspace "12222";;
-+Exception: Pcre2.Error Partial.
-+utop # pcre2_dfa_match ~rex ~flags:[`PARTIAL_SOFT; `DFA_RESTART] ~workspace "2222222";;
-+Exception: Pcre2.Error Partial.
-+utop # pcre2_dfa_exec ~rex ~flags:[`PARTIAL_SOFT; `DFA_RESTART] ~workspace "2222222";;
-+Exception: Pcre2.Error Partial.
-+utop # pcre2_dfa_exec ~rex ~flags:[`PARTIAL_SOFT; `DFA_RESTART] ~workspace "223xxxx";;
-+- : int array = [|0; 3; 0|]
-+```
-+
-+Refer to the `pcre2_dfa_exec` documentation and the `dfa_restart` example for
-+more information.
-+
-+## Contact Information and Contributing
-+
-+Submit bug reports, feature requests, and contributions via the
-+[GitHub issue tracker](https://github.com/camlp5/pcre2-ocaml/issues).
-+
-+For the latest information, visit: <https://github.com/camlp5/pcre2-ocaml>
-diff --git a/bundles/pcre2/pcre2-ocaml/dune b/bundles/pcre2/pcre2-ocaml/dune
-new file mode 100644
-index 000000000..3edaa082b
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/dune
-@@ -0,0 +1,9 @@
-+(env
-+ (dev
-+  (flags
-+   (:standard -w -9 -principal))
-+  (c_flags
-+   (:standard -Wall -pedantic -Wextra -Wunused)))
-+ (release
-+  (ocamlopt_flags
-+   (:standard -O3))))
-diff --git a/bundles/pcre2/pcre2-ocaml/dune-project b/bundles/pcre2/pcre2-ocaml/dune-project
-new file mode 100644
-index 000000000..2635a66a2
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/dune-project
-@@ -0,0 +1,32 @@
-+(lang dune 2.7)
-+
-+(name pcre2)
-+
-+(version 8.0.4)
-+
-+(generate_opam_files true)
-+
-+(source
-+ (github camlp5/pcre2-ocaml))
-+
-+(license "LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception")
-+
-+(homepage "https://github.com/camlp5/pcre2-ocaml")
-+
-+(maintainers "Chet Murthy <chetsky@gmail.com>")
-+
-+(authors "Markus Mottl <markus.mottl@gmail.com>")
-+
-+(package
-+ (name pcre2)
-+ (synopsis
-+   "Bindings to the Perl Compatibility Regular Expressions library (version 2)")
-+ (description
-+   "pcre2-ocaml offers library functions for string pattern matching and\nsubstitution, similar to the functionality offered by the Perl language.")
-+ (depends
-+  (ocaml
-+   (>= 4.08))
-+  dune-compiledb
-+  dune-configurator
-+  (conf-libpcre2-8 :build)
-+  (ounit2 :with-test)))
-diff --git a/bundles/pcre2/pcre2-ocaml/examples/Makefile b/bundles/pcre2/pcre2-ocaml/examples/Makefile
-new file mode 100644
-index 000000000..29dbbf0a4
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/examples/Makefile
-@@ -0,0 +1,9 @@
-+TARGETS = $(addsuffix .bc, cloc count_hash dfa_restart pcre2grep subst)
-+
-+.PHONY: all clean
-+
-+all:
-+	@dune build $(TARGETS)
-+
-+clean:
-+	@dune clean
-diff --git a/bundles/pcre2/pcre2-ocaml/examples/README.md b/bundles/pcre2/pcre2-ocaml/examples/README.md
-new file mode 100644
-index 000000000..d832f042f
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/examples/README.md
-@@ -0,0 +1,48 @@
-+# Examples
-+
-+## `cloc`
-+
-+This program reads C source code from `stdin` and outputs it to `stdout` with
-+comments and empty lines removed. It's useful for counting lines of code.
-+
-+## `count_hash`
-+
-+This program reads text from `stdin`, counts occurrences of identical words
-+separated by whitespace, and prints the result to `stdout`.
-+
-+## `pcre2grep`
-+
-+A grep-like program using Perl-compatible regular expressions. Start the program
-+with the `-help` argument to see its functionality.
-+
-+## `subst`
-+
-+Substitutes text in files using Perl-compatible regular expressions and
-+substitution patterns. Start the program with the `-help` argument to see its
-+functionality.
-+
-+Example invocation:
-+
-+```sh
-+subst '([Tt])ermcap' '$1ermCap' < /etc/termcap
-+```
-+
-+## `dfa_restart`
-+
-+Tests the DFA matching function and its partial match restart capability. Given
-+a pattern, it accepts input incrementally, restarting the prior partial match
-+until the pattern either succeeds or fails.
-+
-+Example interaction:
-+
-+```sh
-+$ dfa_restart.exe 'abc12+3'
-+> abc
-+partial match, provide more input:
-+> 122222
-+partial match, provide more input:
-+> 222
-+partial match, provide more input:
-+> 3
-+match completed: "[|0;1;0|]"
-+```
-diff --git a/bundles/pcre/pcre-ocaml/examples/cloc.ml b/bundles/pcre2/pcre2-ocaml/examples/cloc.ml
-similarity index 97%
-rename from bundles/pcre/pcre-ocaml/examples/cloc.ml
-rename to bundles/pcre2/pcre2-ocaml/examples/cloc.ml
-index 27c7fd3a8..f48376250 100644
---- a/bundles/pcre/pcre-ocaml/examples/cloc.ml
-+++ b/bundles/pcre2/pcre2-ocaml/examples/cloc.ml
-@@ -1,4 +1,4 @@
--open Pcre
-+open Pcre2
- 
- let read_whole_channel ch =
-   let size = 4096 in
-diff --git a/bundles/pcre/pcre-ocaml/examples/count_hash.ml b/bundles/pcre2/pcre2-ocaml/examples/count_hash.ml
-similarity index 62%
-rename from bundles/pcre/pcre-ocaml/examples/count_hash.ml
-rename to bundles/pcre2/pcre2-ocaml/examples/count_hash.ml
-index 98d16bc50..47118b684 100644
---- a/bundles/pcre/pcre-ocaml/examples/count_hash.ml
-+++ b/bundles/pcre2/pcre2-ocaml/examples/count_hash.ml
-@@ -1,6 +1,8 @@
- open Hashtbl
- 
- let hash = create 1973
--let add_string s = try incr (find hash s) with Not_found -> add hash s (ref 1);;
--Pcre.foreach_line (fun line -> List.iter add_string (Pcre.split line));
-+let add_string s = try incr (find hash s) with Not_found -> add hash s (ref 1)
-+;;
-+
-+Pcre2.foreach_line (fun line -> List.iter add_string (Pcre2.split line));
- iter (fun k v -> Printf.printf "%4d\t%s\n" !v k) hash
-diff --git a/bundles/pcre2/pcre2-ocaml/examples/dfa_restart.ml b/bundles/pcre2/pcre2-ocaml/examples/dfa_restart.ml
-new file mode 100644
-index 000000000..882a1f355
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/examples/dfa_restart.ml
-@@ -0,0 +1,40 @@
-+open Pcre2
-+open Printf
-+
-+let show_array arr =
-+  Array.map string_of_int arr
-+  |> Array.to_list |> String.concat ";" |> sprintf "[|%s|]"
-+
-+let new_workspace () = Array.make 50 0
-+
-+let () =
-+  let pat =
-+    if Array.length Sys.argv > 1 then Sys.argv.(1)
-+    else (
-+      eprintf "%s: expected pattern argument\n" Sys.argv.(0);
-+      exit 1)
-+  in
-+  let rex = regexp pat in
-+  let rec find_match flags workspace =
-+    print_string "> ";
-+    let line, eof =
-+      try (read_line (), false) with End_of_file -> ("", true)
-+    in
-+    match pcre2_dfa_match ~rex ~flags ~workspace line with
-+    | res ->
-+        printf "match completed: %S\n" (show_array res);
-+        if not eof then (
-+          printf "\n *input & workspace reset*\n";
-+          find_match [ `PARTIAL_SOFT ] (new_workspace ()))
-+    | exception Error Partial ->
-+        printf "partial match, provide more input:\n";
-+        find_match [ `DFA_RESTART; `PARTIAL_SOFT ] workspace
-+    | exception exn ->
-+        (match exn with
-+        | Not_found -> eprintf "pattern match failed\n"
-+        | Error WorkspaceSize -> eprintf "need larger workspace vector\n"
-+        | Error (InternalError s) -> eprintf "internal error: %s\n" s
-+        | exn -> raise exn);
-+        exit 1
-+  in
-+  find_match [ `PARTIAL_SOFT ] (new_workspace ())
-diff --git a/bundles/pcre2/pcre2-ocaml/examples/dune b/bundles/pcre2/pcre2-ocaml/examples/dune
-new file mode 100644
-index 000000000..612c60c04
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/examples/dune
-@@ -0,0 +1,4 @@
-+(executables
-+ (names cloc count_hash pcre2grep subst dfa_restart)
-+ (libraries pcre2)
-+ (modes byte exe))
-diff --git a/bundles/pcre2/pcre2-ocaml/examples/pcre2grep.ml b/bundles/pcre2/pcre2-ocaml/examples/pcre2grep.ml
-new file mode 100644
-index 000000000..5a8e02e41
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/examples/pcre2grep.ml
-@@ -0,0 +1,128 @@
-+open Pcre2
-+open Printf
-+
-+let filenames = ref true
-+and filenames_only = ref false
-+and count_only = ref false
-+and invert = ref false
-+and number = ref false
-+and silent = ref false
-+and whole_lines = ref false
-+
-+let parse_args () =
-+  let ignore_case = ref false and pat = ref None and files = ref [] in
-+
-+  let c = ("-c", Arg.Set count_only, "Count lines only.")
-+  and h =
-+    ( "-h",
-+      Arg.Clear filenames,
-+      "Suppress printing of filenames when searching multiple files." )
-+  and i = ("-i", Arg.Set ignore_case, "Ignore case.")
-+  and l =
-+    ( "-l",
-+      Arg.Set filenames_only,
-+      "Only print names of files containing matching lines (once)." )
-+  and n =
-+    ("-n", Arg.Set number, "Precede each line by its line number in the file.")
-+  and s =
-+    ( "-s",
-+      Arg.Set silent,
-+      "Display nothing but error messages. Exit status indicates match." )
-+  and v =
-+    ("-v", Arg.Set invert, "Invert sense of the match: finds nonmatching lines.")
-+  and x =
-+    ( "-x",
-+      Arg.Set whole_lines,
-+      "Force the pattern to be anchored and to match the entire line." )
-+  and usage =
-+    "Usage: pcre2grep [options] pattern [file] ...\n\n\
-+     Searches files for character patterns.\n"
-+  and anon_arg arg =
-+    if !pat = None then pat := Some arg else files := arg :: !files
-+  in
-+
-+  let args = [ c; h; i; l; n; s; v; x ] in
-+  Arg.parse args anon_arg usage;
-+
-+  let flags =
-+    let flag_list = if !ignore_case then [ `CASELESS ] else [] in
-+    if !whole_lines then `ANCHORED :: flag_list else flag_list
-+  in
-+
-+  let rex =
-+    match !pat with
-+    | Some pat -> regexp ~flags pat
-+    | None ->
-+        eprintf "%s: not enough arguments!\n" Sys.argv.(0);
-+        Arg.usage args usage;
-+        exit 2
-+  in
-+  (rex, List.rev !files)
-+
-+let _ =
-+  let rex, files = parse_args () and rfl = rflags [] in
-+
-+  let _, ovector = make_ovector rex in
-+
-+  let pcre2grep file name =
-+    let ret_code = ref 1
-+    and linenumber = ref 0
-+    and count = ref 0
-+    and stdin_print_name () =
-+      match name with
-+      | Some filename -> print_endline filename
-+      | None -> print_endline "<stdin>"
-+    and print_name () =
-+      match name with Some name -> printf "%s:" name | None -> ()
-+    in
-+
-+    let try_match line =
-+      let matched =
-+        try
-+          unsafe_pcre2_match rfl rex ~pos:0 ~subj_start:0 ~subj:line ovector
-+            None;
-+          if !whole_lines && ovector.(1) <> String.length line then false
-+          else true
-+        with Not_found -> false
-+      in
-+
-+      incr linenumber;
-+
-+      if matched <> !invert then (
-+        if !count_only then incr count
-+        else if !filenames_only then (
-+          stdin_print_name ();
-+          raise Exit)
-+        else if !silent then raise Exit
-+        else (
-+          print_name ();
-+          if !number then printf "%d:" !linenumber;
-+          print_endline line);
-+        ret_code := 0)
-+    in
-+
-+    try
-+      foreach_line ~ic:file try_match;
-+      if !count_only then (
-+        print_name ();
-+        printf "%d\n" !count);
-+      !ret_code
-+    with Exit -> 0
-+  in
-+
-+  if files = [] then exit (pcre2grep stdin None);
-+
-+  if List.length files = 1 then filenames := false;
-+  if !filenames_only then filenames := true;
-+
-+  let collect ret_code filename =
-+    try
-+      let file = open_in filename in
-+      let frc = pcre2grep file (if !filenames then Some filename else None) in
-+      close_in file;
-+      if frc = 0 && ret_code = 1 then 0 else ret_code
-+    with Sys_error msg ->
-+      prerr_endline msg;
-+      2
-+  in
-+  exit (List.fold_left collect 1 files)
-diff --git a/bundles/pcre2/pcre2-ocaml/examples/subst.ml b/bundles/pcre2/pcre2-ocaml/examples/subst.ml
-new file mode 100644
-index 000000000..d9ec61c7a
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/examples/subst.ml
-@@ -0,0 +1,57 @@
-+open Pcre2
-+
-+let parse_args () =
-+  let quick = ref false
-+  and first = ref false
-+  and ignore_case = ref false
-+  and offset = ref 0
-+  and pat = ref None
-+  and substr = ref None in
-+
-+  let q =
-+    ( "-q",
-+      Arg.Set quick,
-+      "Quick replacement. Interpretes substitution as plain text." )
-+  and f = ("-f", Arg.Set first, "Replace first occurrence in line only.")
-+  and i = ("-i", Arg.Set ignore_case, "Ignore case.")
-+  and ofs =
-+    ("-ofs", Arg.Int (fun n -> offset := n), "Start matching at column n.")
-+  and usage =
-+    "Usage: subst [-q] [-f] [-i] [-ofs offset] pattern substitution\n\n\
-+     Reads lines from standard input and replaces occurrences of\n\
-+     the PERL-style regular expression \"pattern\" with \"substitution\",\n\
-+     printing the result to standard output.\n\
-+     In default mode the contents of \"substitution\" will be interpreted\n\
-+     similarly to its equivalent in PERL.\n"
-+  and anon_arg arg =
-+    match (!pat, !substr) with
-+    | None, _ -> pat := Some arg
-+    | _, None -> substr := Some arg
-+    | _ -> raise (Arg.Bad "too many arguments!")
-+  in
-+
-+  let args = [ q; f; i; ofs ] in
-+  Arg.parse args anon_arg usage;
-+
-+  let flags = if !ignore_case then [ `CASELESS ] else [] in
-+
-+  let rex, sstr =
-+    match (!pat, !substr) with
-+    | Some rex, Some sstr -> (regexp ~flags rex, sstr)
-+    | _ ->
-+        prerr_endline (Sys.argv.(0) ^ ": not enough arguments!");
-+        Arg.usage args usage;
-+        exit 1
-+  in
-+
-+  match (!quick, !first) with
-+  | false, false -> fun s -> replace ~rex ~pos:!offset ~templ:sstr s
-+  | true, false -> fun s -> qreplace ~rex ~pos:!offset ~templ:sstr s
-+  | false, true -> fun s -> replace_first ~rex ~pos:!offset ~templ:sstr s
-+  | true, true -> fun s -> qreplace_first ~rex ~pos:!offset ~templ:sstr s
-+
-+let _ =
-+  let substitute = parse_args () in
-+  foreach_line (fun line ->
-+      try print_endline (substitute line)
-+      with Invalid_argument _ -> print_endline line)
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/Makefile b/bundles/pcre2/pcre2-ocaml/lib/Makefile
-new file mode 100644
-index 000000000..ef5f07cfe
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/Makefile
-@@ -0,0 +1,15 @@
-+TARGETS = pcre2.cma libpcre2_stubs.a
-+
-+.PHONY: all clean clean-compile-commands
-+
-+all: compile_commands.json
-+	@dune build $(TARGETS)
-+
-+clean: clean-compile-commands
-+	@dune clean
-+
-+compile_commands.json: config/dune config/discover.ml $(wildcard *.c *.h)
-+	@dune rules | dune-compiledb
-+
-+clean-compile-commands:
-+	@rm -f compile_commands.json
-diff --git a/bundles/pcre/pcre-ocaml/src/config/Makefile b/bundles/pcre2/pcre2-ocaml/lib/config/Makefile
-similarity index 100%
-rename from bundles/pcre/pcre-ocaml/src/config/Makefile
-rename to bundles/pcre2/pcre2-ocaml/lib/config/Makefile
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/config/discover.ml b/bundles/pcre2/pcre2-ocaml/lib/config/discover.ml
-new file mode 100644
-index 000000000..94524c65c
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/config/discover.ml
-@@ -0,0 +1,14 @@
-+let () =
-+  let module C = Configurator.V1 in
-+  C.main ~name:"pcre2" (fun c ->
-+      let default : C.Pkg_config.package_conf =
-+        { libs = [ "-lpcre2-8" ]; cflags = [] }
-+      in
-+      let conf =
-+        match C.Pkg_config.get c with
-+        | None -> default
-+        | Some pc ->
-+            Option.value (C.Pkg_config.query pc ~package:"libpcre2-8") ~default
-+      in
-+      C.Flags.write_sexp "c_flags.sexp" conf.cflags;
-+      C.Flags.write_sexp "c_library_flags.sexp" conf.libs)
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/config/dune b/bundles/pcre2/pcre2-ocaml/lib/config/dune
-new file mode 100644
-index 000000000..ec1eb67f6
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/config/dune
-@@ -0,0 +1,4 @@
-+(executables
-+ (names discover)
-+ (libraries dune.configurator)
-+ (modes byte exe))
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/dune b/bundles/pcre2/pcre2-ocaml/lib/dune
-new file mode 100644
-index 000000000..22e570f07
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/dune
-@@ -0,0 +1,18 @@
-+(library
-+ (public_name pcre2)
-+ (foreign_stubs
-+  (language c)
-+  (names pcre2_stubs)
-+  (flags
-+   (:standard)
-+   (:include c_flags.sexp)
-+   -O2
-+   -fPIC
-+   -DPIC))
-+ (c_library_flags
-+  (:include c_library_flags.sexp)))
-+
-+(rule
-+ (targets c_flags.sexp c_library_flags.sexp)
-+ (action
-+  (run ./config/discover.exe)))
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/pcre2.ml b/bundles/pcre2/pcre2-ocaml/lib/pcre2.ml
-new file mode 100644
-index 000000000..b8e2c3c41
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/pcre2.ml
-@@ -0,0 +1,1231 @@
-+(* PCRE2-OCAML - Perl Compatibility Regular Expressions for OCaml
-+
-+   Copyright © 1999- Markus Mottl <markus.mottl@gmail.com>
-+
-+   This library is free software; you can redistribute it and/or modify it under
-+   the terms of the GNU Lesser General Public License as published by the Free
-+   Software Foundation; either version 2.1 of the License, or (at your option)
-+   any later version.
-+
-+   This library 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 Lesser General Public License for more
-+   details.
-+
-+   You should have received a copy of the GNU Lesser General Public License
-+   along with this library; if not, write to the Free Software Foundation, Inc.,
-+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *)
-+
-+(* Public exceptions and their registration with the C runtime *)
-+
-+open Printf
-+
-+type error =
-+  | Partial
-+  | BadPattern of string * int
-+  | BadUTF
-+  | BadUTFOffset
-+  | MatchLimit
-+  | DepthLimit
-+  | WorkspaceSize
-+  | InternalError of string
-+
-+let string_of_error = function
-+  | Partial -> "Partial"
-+  | BadPattern (msg, pos) -> sprintf "Pcre2.BadPattern(%S, pos=%i)" msg pos
-+  | BadUTF -> "BadUTF"
-+  | BadUTFOffset -> "BadUTFOffset"
-+  | MatchLimit -> "MatchLimit"
-+  | DepthLimit -> "DepthLimit"
-+  | WorkspaceSize -> "WorkspaceSize"
-+  | InternalError msg -> sprintf "InternalError(%S)" msg
-+
-+exception Error of error
-+exception Backtrack
-+exception Regexp_or of string * error
-+
-+let string_of_exn = function
-+  | Error error -> Some (sprintf "Pcre2.Error(%s)" (string_of_error error))
-+  | Backtrack -> Some "Pcre2.Backtrack"
-+  | Regexp_or (pat, error) ->
-+      Some (sprintf "Pcre2.Regexp_or(pat=%S, %s)" pat (string_of_error error))
-+  | _not_from_pcre -> None
-+
-+let () = Printexc.register_printer string_of_exn
-+
-+(* Puts exceptions into global C-variables for fast retrieval *)
-+external pcre2_ocaml_init : unit -> unit = "pcre2_ocaml_init"
-+
-+(* Registers exceptions with the C runtime and caches polymorphic variants *)
-+let () =
-+  Callback.register_exception "Pcre2.Error" (Error (InternalError ""));
-+  Callback.register_exception "Pcre2.Backtrack" Backtrack;
-+  pcre2_ocaml_init ()
-+
-+(* Compilation and runtime flags and their conversion functions *)
-+
-+type icflag = int64
-+type irflag = int64
-+
-+(* Compilation flags *)
-+
-+type cflag =
-+  [ `ALLOW_EMPTY_CLASS
-+  | `ALT_BSUX
-+  | `ALT_CIRCUMFLEX
-+  | `ALT_VERBNAMES
-+  | `ANCHORED
-+  | `AUTO_CALLOUT
-+  | `CASELESS
-+  | `DOLLAR_ENDONLY
-+  | `DOTALL
-+  | `DUPNAMES
-+  | `ENDANCHORED
-+  | `EXTENDED
-+  | `EXTENDED_MORE
-+  | `FIRSTLINE
-+  | `LITERAL
-+  | `MATCH_INVALID_UTF
-+  | `MATCH_UNSET_BACKREF
-+  | `MULTILINE
-+  | `NEVER_BACKSLASH_C
-+  | `NEVER_UCP
-+  | `NEVER_UTF
-+  | `NO_AUTO_CAPTURE
-+  | `NO_AUTO_POSSESS
-+  | `NO_DOTSTAR_ANCHOR
-+  | `NO_START_OPTIMIZE
-+  | `NO_UTF_CHECK
-+  | `UCP
-+  | `UNGREEDY
-+  | `USE_OFFSET_LIMIT
-+  | `UTF ]
-+
-+let int_of_cflag = function
-+  | `ALLOW_EMPTY_CLASS -> 0x00000001L
-+  | `ALT_BSUX -> 0x00000002L
-+  | `AUTO_CALLOUT -> 0x00000004L
-+  | `CASELESS -> 0x00000008L
-+  | `DOLLAR_ENDONLY -> 0x00000010L
-+  | `DOTALL -> 0x00000020L
-+  | `DUPNAMES -> 0x00000040L
-+  | `EXTENDED -> 0x00000080L
-+  | `FIRSTLINE -> 0x00000100L
-+  | `MATCH_UNSET_BACKREF -> 0x00000200L
-+  | `MULTILINE -> 0x00000400L
-+  | `NEVER_UCP -> 0x00000800L
-+  | `NEVER_UTF -> 0x00001000L
-+  | `NO_AUTO_CAPTURE -> 0x00002000L
-+  | `NO_AUTO_POSSESS -> 0x00004000L
-+  | `NO_DOTSTAR_ANCHOR -> 0x00008000L
-+  | `NO_START_OPTIMIZE -> 0x00010000L
-+  | `UCP -> 0x00020000L
-+  | `UNGREEDY -> 0x00040000L
-+  | `UTF -> 0x00080000L
-+  | `NEVER_BACKSLASH_C -> 0x00100000L
-+  | `ALT_CIRCUMFLEX -> 0x00200000L
-+  | `ALT_VERBNAMES -> 0x00400000L
-+  | `USE_OFFSET_LIMIT -> 0x00800000L
-+  | `EXTENDED_MORE -> 0x01000000L
-+  | `LITERAL -> 0x02000000L
-+  | `MATCH_INVALID_UTF -> 0x04000000L
-+  | `ENDANCHORED -> 0x20000000L
-+  | `NO_UTF_CHECK -> 0x40000000L
-+  | `ANCHORED -> 0x80000000L
-+
-+let coll_icflag icflag flag = Int64.logor (int_of_cflag flag) icflag
-+let cflags flags = List.fold_left coll_icflag 0L flags
-+
-+let cflag_of_int = function
-+  | 0x00000001L -> `ALLOW_EMPTY_CLASS
-+  | 0x00000002L -> `ALT_BSUX
-+  | 0x00000004L -> `AUTO_CALLOUT
-+  | 0x00000008L -> `CASELESS
-+  | 0x00000010L -> `DOLLAR_ENDONLY
-+  | 0x00000020L -> `DOTALL
-+  | 0x00000040L -> `DUPNAMES
-+  | 0x00000080L -> `EXTENDED
-+  | 0x00000100L -> `FIRSTLINE
-+  | 0x00000200L -> `MATCH_UNSET_BACKREF
-+  | 0x00000400L -> `MULTILINE
-+  | 0x00000800L -> `NEVER_UCP
-+  | 0x00001000L -> `NEVER_UTF
-+  | 0x00002000L -> `NO_AUTO_CAPTURE
-+  | 0x00004000L -> `NO_AUTO_POSSESS
-+  | 0x00008000L -> `NO_DOTSTAR_ANCHOR
-+  | 0x00010000L -> `NO_START_OPTIMIZE
-+  | 0x00020000L -> `UCP
-+  | 0x00040000L -> `UNGREEDY
-+  | 0x00080000L -> `UTF
-+  | 0x00100000L -> `NEVER_BACKSLASH_C
-+  | 0x00200000L -> `ALT_CIRCUMFLEX
-+  | 0x00400000L -> `ALT_VERBNAMES
-+  | 0x00800000L -> `USE_OFFSET_LIMIT
-+  | 0x01000000L -> `EXTENDED_MORE
-+  | 0x02000000L -> `LITERAL
-+  | 0x04000000L -> `MATCH_INVALID_UTF
-+  | 0x20000000L -> `ENDANCHORED
-+  | 0x40000000L -> `NO_UTF_CHECK
-+  | 0x80000000L -> `ANCHORED
-+  | _ -> failwith "Pcre2.cflag_list: unknown compilation flag"
-+
-+let all_cflags =
-+  [
-+    0x00000001L;
-+    0x00000002L;
-+    0x00000004L;
-+    0x00000008L;
-+    0x00000010L;
-+    0x00000020L;
-+    0x00000040L;
-+    0x00000080L;
-+    0x00000100L;
-+    0x00000200L;
-+    0x00000400L;
-+    0x00000800L;
-+    0x00001000L;
-+    0x00002000L;
-+    0x00004000L;
-+    0x00008000L;
-+    0x00010000L;
-+    0x00020000L;
-+    0x00040000L;
-+    0x00080000L;
-+    0x00100000L;
-+    0x00200000L;
-+    0x00400000L;
-+    0x00800000L;
-+    0x01000000L;
-+    0x02000000L;
-+    0x04000000L;
-+    0x20000000L;
-+    0x40000000L;
-+    0x80000000L;
-+  ]
-+
-+let cflag_list icflags =
-+  let coll flag_list flag =
-+    if Int64.equal (Int64.logand icflags flag) 0L then flag_list
-+    else cflag_of_int flag :: flag_list
-+  in
-+  List.fold_left coll [] all_cflags
-+
-+(* Runtime flags *)
-+
-+type rflag =
-+  [ `ANCHORED
-+  | `COPY_MATCHED_SUBJECT
-+  | `DFA_RESTART
-+  | `DFA_SHORTEST
-+  | `ENDANCHORED
-+  | `NOTBOL
-+  | `NOTEOL
-+  | `NOTEMPTY
-+  | `NOTEMPTY_ATSTART
-+  | `NO_JIT
-+  | `NO_UTF_CHECK
-+  | `PARTIAL_HARD
-+  | `PARTIAL_SOFT ]
-+
-+let int_of_rflag = function
-+  | `NOTBOL -> 0x00000001L
-+  | `NOTEOL -> 0x00000002L
-+  | `NOTEMPTY -> 0x00000004L
-+  | `NOTEMPTY_ATSTART -> 0x00000008L
-+  | `PARTIAL_SOFT -> 0x00000010L
-+  | `PARTIAL_HARD -> 0x00000020L
-+  | `DFA_RESTART -> 0x00000040L
-+  | `DFA_SHORTEST -> 0x00000080L
-+  | `NO_JIT -> 0x00002000L
-+  | `COPY_MATCHED_SUBJECT -> 0x00004000L
-+  | `ENDANCHORED -> 0x20000000L
-+  | `NO_UTF_CHECK -> 0x40000000L
-+  | `ANCHORED -> 0x80000000L
-+
-+let coll_irflag irflag flag = Int64.logor (int_of_rflag flag) irflag
-+let rflags flags = List.fold_left coll_irflag 0L flags
-+
-+let rflag_of_int = function
-+  | 0x00000001L -> `NOTBOL
-+  | 0x00000002L -> `NOTEOL
-+  | 0x00000004L -> `NOTEMPTY
-+  | 0x00000008L -> `NOTEMPTY_ATSTART
-+  | 0x00000010L -> `PARTIAL_SOFT
-+  | 0x00000020L -> `PARTIAL_HARD
-+  | 0x00000040L -> `DFA_RESTART
-+  | 0x00000080L -> `DFA_SHORTEST
-+  | 0x00002000L -> `NO_JIT
-+  | 0x00004000L -> `COPY_MATCHED_SUBJECT
-+  | 0x20000000L -> `ENDANCHORED
-+  | 0x40000000L -> `NO_UTF_CHECK
-+  | 0x80000000L -> `ANCHORED
-+  | _ -> failwith "Pcre2.rflag_list: unknown runtime flag"
-+
-+let all_rflags =
-+  [
-+    0x00000001L;
-+    0x00000002L;
-+    0x00000004L;
-+    0x00000008L;
-+    0x00000010L;
-+    0x00000020L;
-+    0x00000040L;
-+    0x00000080L;
-+    0x00002000L;
-+    0x00004000L;
-+    0x20000000L;
-+    0x40000000L;
-+    0x80000000L;
-+  ]
-+
-+let rflag_list irflags =
-+  let coll flag_list flag =
-+    if Int64.equal (Int64.logand irflags flag) 0L then flag_list
-+    else rflag_of_int flag :: flag_list
-+  in
-+  List.fold_left coll [] all_rflags
-+
-+(* Information on the PCRE2-configuration (build-time options) *)
-+
-+external pcre2_version : unit -> string = "pcre2_version_stub"
-+
-+external pcre2_config_unicode : unit -> bool = "pcre2_config_unicode_stub"
-+[@@noalloc]
-+
-+external pcre2_config_newline : unit -> char = "pcre2_config_newline_stub"
-+[@@noalloc]
-+
-+external pcre2_config_link_size : unit -> (int[@untagged])
-+  = "pcre2_config_link_size_stub_bc" "pcre2_config_link_size_stub"
-+[@@noalloc]
-+
-+external pcre2_config_match_limit : unit -> (int[@untagged])
-+  = "pcre2_config_match_limit_stub_bc" "pcre2_config_match_limit_stub"
-+[@@noalloc]
-+
-+external pcre2_config_depth_limit : unit -> (int[@untagged])
-+  = "pcre2_config_depth_limit_stub_bc" "pcre2_config_depth_limit_stub"
-+[@@noalloc]
-+
-+external pcre2_config_stackrecurse : unit -> bool
-+  = "pcre2_config_stackrecurse_stub"
-+[@@noalloc]
-+
-+let version = pcre2_version ()
-+let config_unicode = pcre2_config_unicode ()
-+let config_newline = pcre2_config_newline ()
-+let config_link_size = pcre2_config_link_size ()
-+let config_match_limit = pcre2_config_match_limit ()
-+let config_depth_limit = pcre2_config_depth_limit ()
-+let config_stackrecurse = pcre2_config_stackrecurse ()
-+
-+(* Information on patterns *)
-+
-+type firstcodeunit_info = [ `Char of char | `Start_only | `ANCHORED ]
-+type regexp
-+
-+external options : regexp -> (icflag[@unboxed])
-+  = "pcre2_argoptions_stub_bc" "pcre2_argoptions_stub"
-+
-+external size : regexp -> (int[@untagged])
-+  = "pcre2_size_stub_bc" "pcre2_size_stub"
-+
-+external capturecount : regexp -> (int[@untagged])
-+  = "pcre2_capturecount_stub_bc" "pcre2_capturecount_stub"
-+
-+external backrefmax : regexp -> (int[@untagged])
-+  = "pcre2_backrefmax_stub_bc" "pcre2_backrefmax_stub"
-+
-+external namecount : regexp -> (int[@untagged])
-+  = "pcre2_namecount_stub_bc" "pcre2_namecount_stub"
-+
-+external nameentrysize : regexp -> (int[@untagged])
-+  = "pcre2_nameentrysize_stub_bc" "pcre2_nameentrysize_stub"
-+
-+external names : regexp -> string array = "pcre2_names_stub"
-+
-+external firstcodeunit : regexp -> firstcodeunit_info
-+  = "pcre2_firstcodeunit_stub"
-+
-+external lastcodeunit : regexp -> char option = "pcre2_lastcodeunit_stub"
-+
-+(* Compilation of patterns *)
-+
-+type chtables
-+
-+external maketables : unit -> chtables = "pcre2_maketables_stub"
-+
-+external compile : (icflag[@unboxed]) -> chtables option -> string -> regexp
-+  = "pcre2_compile_stub_bc" "pcre2_compile_stub"
-+
-+(* external get_match_limit : regexp -> int option =
-+   "pcre2_get_match_limit_stub" *)
-+
-+(* Internal use only! *)
-+external set_imp_match_limit : regexp -> (int[@untagged]) -> regexp
-+  = "pcre2_set_imp_match_limit_stub_bc" "pcre2_set_imp_match_limit_stub"
-+[@@noalloc]
-+
-+(* external get_depth_limit : regexp -> int option =
-+   "pcre2_get_depth_limit_stub" *)
-+
-+(* Internal use only! *)
-+external set_imp_depth_limit : regexp -> (int[@untagged]) -> regexp
-+  = "pcre2_set_imp_depth_limit_stub_bc" "pcre2_set_imp_depth_limit_stub"
-+[@@noalloc]
-+
-+(* TODO implement jit using new pcre2_jit_compile api *)
-+let regexp
-+    (* ?(jit_compile = false) *)
-+    ?limit ?depth_limit ?(iflags = 0L) ?flags ?chtables pat =
-+  let rex =
-+    match flags with
-+    | Some flag_list -> compile (cflags flag_list) chtables pat
-+    | _ -> compile iflags chtables pat
-+  in
-+  let rex =
-+    match limit with None -> rex | Some lim -> set_imp_match_limit rex lim
-+  in
-+  match depth_limit with None -> rex | Some lim -> set_imp_depth_limit rex lim
-+
-+let regexp_or (* ?jit_compile *) ?limit ?depth_limit ?(iflags = 0L) ?flags
-+    ?chtables pats =
-+  let check pat =
-+    try ignore (regexp ~iflags ?flags ?chtables pat)
-+    with Error error -> raise (Regexp_or (pat, error))
-+  in
-+  List.iter check pats;
-+  let big_pat =
-+    let cnv pat = "(?:" ^ pat ^ ")" in
-+    String.concat "|" (List.rev (List.rev_map cnv pats))
-+  in
-+  regexp (* ?jit_compile *) ?limit ?depth_limit ~iflags ?flags ?chtables big_pat
-+
-+let bytes_unsafe_blit_string str str_ofs bts bts_ofs len =
-+  let str_bts = Bytes.unsafe_of_string str in
-+  Bytes.unsafe_blit str_bts str_ofs bts bts_ofs len
-+
-+let string_unsafe_sub str ofs len =
-+  let res = Bytes.create len in
-+  bytes_unsafe_blit_string str ofs res 0 len;
-+  Bytes.unsafe_to_string res
-+
-+let quote s =
-+  let len = String.length s in
-+  let buf = Bytes.create (len lsl 1) in
-+  let pos = ref 0 in
-+  for i = 0 to len - 1 do
-+    match String.unsafe_get s i with
-+    | ('\\' | '^' | '$' | '.' | '[' | '|' | '(' | ')' | '?' | '*' | '+' | '{')
-+      as c ->
-+        Bytes.unsafe_set buf !pos '\\';
-+        incr pos;
-+        Bytes.unsafe_set buf !pos c;
-+        incr pos
-+    | c ->
-+        Bytes.unsafe_set buf !pos c;
-+        incr pos
-+  done;
-+  string_unsafe_sub (Bytes.unsafe_to_string buf) 0 !pos
-+
-+(* Matching of patterns and subpattern extraction *)
-+
-+(* Default regular expression when none is provided by the user *)
-+let def_rex = regexp (* ~jit_compile:true *) "\\s+"
-+
-+type substrings = string * int array
-+
-+type callout_data = {
-+  callout_number : int;
-+  substrings : substrings;
-+  start_match : int;
-+  current_position : int;
-+  capture_top : int;
-+  capture_last : int;
-+  pattern_position : int;
-+  next_item_length : int;
-+}
-+
-+type callout = callout_data -> unit
-+
-+let get_subject (subj, _) = subj
-+let num_of_subs (_, ovector) = Array.length ovector / 3
-+
-+let get_offset_start ovector str_num =
-+  if str_num < 0 || str_num >= Array.length ovector / 3 then
-+    invalid_arg "Pcre2.get_offset_start: illegal offset";
-+  let offset = str_num lsl 1 in
-+  (offset, Array.unsafe_get ovector offset)
-+
-+let get_substring_aux (subj, ovector) offset start =
-+  if start < 0 then raise Not_found
-+  else
-+    string_unsafe_sub subj start (Array.unsafe_get ovector (offset + 1) - start)
-+
-+let get_substring ((_, ovector) as substrings) str_num =
-+  let offset, start = get_offset_start ovector str_num in
-+  get_substring_aux substrings offset start
-+
-+let get_substring_ofs (_subj, ovector) str_num =
-+  let offset, start = get_offset_start ovector str_num in
-+  if start < 0 then raise Not_found
-+  else (start, Array.unsafe_get ovector (offset + 1))
-+
-+let unsafe_get_substring ((_, ovector) as substrings) str_num =
-+  let offset = str_num lsl 1 in
-+  try get_substring_aux substrings offset (Array.unsafe_get ovector offset)
-+  with Not_found -> ""
-+
-+let get_substrings ?(full_match = true) ((_, ovector) as substrings) =
-+  if full_match then
-+    Array.init (Array.length ovector / 3) (unsafe_get_substring substrings)
-+  else
-+    let len = (Array.length ovector / 3) - 1 in
-+    Array.init len (fun n -> unsafe_get_substring substrings (n + 1))
-+
-+let unsafe_get_opt_substring ((_, ovector) as substrings) str_num =
-+  let offset = str_num lsl 1 in
-+  try
-+    let start = Array.unsafe_get ovector offset in
-+    let str = get_substring_aux substrings offset start in
-+    Some str
-+  with Not_found -> None
-+
-+let get_opt_substrings ?(full_match = true) ((_, ovector) as substrings) =
-+  if full_match then
-+    Array.init (Array.length ovector / 3) (unsafe_get_opt_substring substrings)
-+  else
-+    let len = (Array.length ovector / 3) - 1 in
-+    Array.init len (fun n -> unsafe_get_opt_substring substrings (n + 1))
-+
-+external get_stringnumber : regexp -> string -> (int[@untagged])
-+  = "pcre2_substring_number_from_name_stub_bc"
-+    "pcre2_substring_number_from_name_stub"
-+
-+let get_named_substring rex name substrings =
-+  get_substring substrings (get_stringnumber rex name)
-+
-+let get_named_substring_ofs rex name substrings =
-+  get_substring_ofs substrings (get_stringnumber rex name)
-+
-+external unsafe_pcre2_match :
-+  (irflag[@unboxed]) ->
-+  regexp ->
-+  pos:(int[@untagged]) ->
-+  subj_start:(int[@untagged]) ->
-+  subj:string ->
-+  int array ->
-+  callout option ->
-+  unit = "pcre2_match_stub_bc" "pcre2_match_stub"
-+
-+let make_ovector rex =
-+  let subgroups1 = capturecount rex + 1 in
-+  let subgroups2 = subgroups1 lsl 1 in
-+  (subgroups2, Array.make (subgroups1 + subgroups2) 0)
-+
-+external unsafe_pcre2_dfa_match :
-+  (irflag[@unboxed]) ->
-+  regexp ->
-+  pos:(int[@untagged]) ->
-+  subj_start:(int[@untagged]) ->
-+  subj:string ->
-+  int array ->
-+  callout option ->
-+  workspace:int array ->
-+  unit = "pcre2_dfa_match_stub_bc" "pcre2_match_stub0"
-+
-+let pcre2_dfa_match ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
-+    ?callout ?(workspace = Array.make 20 0) subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let _, ovector = make_ovector rex in
-+  unsafe_pcre2_dfa_match iflags rex ~pos ~subj_start:0 ~subj ovector callout
-+    ~workspace;
-+  ovector
-+
-+let pcre2_match ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0) ?callout
-+    subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let _, ovector = make_ovector rex in
-+  unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
-+  ovector
-+
-+let exec ?iflags ?flags ?rex ?pat ?pos ?callout subj =
-+  (subj, pcre2_match ?iflags ?flags ?rex ?pat ?pos ?callout subj)
-+
-+let next_match ?iflags ?flags ?rex ?pat ?(pos = 0) ?callout (subj, ovector) =
-+  let pos = Array.unsafe_get ovector 1 + pos in
-+  let subj_len = String.length subj in
-+  if pos < 0 || pos > subj_len then
-+    invalid_arg "Pcre2.next_match: illegal offset";
-+  (subj, pcre2_match ?iflags ?flags ?rex ?pat ~pos ?callout subj)
-+
-+let rec copy_lst ar n = function
-+  | [] -> ar
-+  | h :: t ->
-+      Array.unsafe_set ar n h;
-+      copy_lst ar (n - 1) t
-+
-+let exec_all ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?pos ?callout subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let ((_, ovector) as sstrs) = exec ~iflags ~rex ?pos ?callout subj in
-+  let null_flags = Int64.logor iflags 0x00000004L in
-+  (* `NOTEMPTY *)
-+  let subj_len = String.length subj in
-+  let rec loop pos ((subj, ovector) as sstrs) n lst =
-+    let maybe_ovector =
-+      try
-+        let first = Array.unsafe_get ovector 0 in
-+        if first = pos && Array.unsafe_get ovector 1 = pos then
-+          if pos = subj_len then None
-+          else Some (pcre2_match ~iflags:null_flags ~rex ~pos ?callout subj)
-+        else Some (pcre2_match ~iflags ~rex ~pos ?callout subj)
-+      with Not_found -> None
-+    in
-+    match maybe_ovector with
-+    | Some ovector ->
-+        let new_pos = Array.unsafe_get ovector 1 in
-+        loop new_pos (subj, ovector) (n + 1) (sstrs :: lst)
-+    | None -> copy_lst (Array.make (n + 1) sstrs) (n - 1) lst
-+  in
-+  loop (Array.unsafe_get ovector 1) sstrs 0 []
-+
-+let extract ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
-+  get_substrings ?full_match (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
-+
-+let extract_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
-+  get_opt_substrings ?full_match
-+    (exec ?iflags ?flags ?rex ?pat ?pos ?callout subj)
-+
-+let extract_all ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
-+  let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
-+  Array.map (get_substrings ?full_match) many_sstrs
-+
-+let extract_all_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj =
-+  let many_sstrs = exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj in
-+  Array.map (get_opt_substrings ?full_match) many_sstrs
-+
-+let pmatch ?iflags ?flags ?rex ?pat ?pos ?callout subj =
-+  try
-+    ignore (pcre2_match ?iflags ?flags ?rex ?pat ?pos ?callout subj);
-+    true
-+  with Not_found -> false
-+
-+(* String substitution *)
-+
-+(* Elements of a substitution pattern *)
-+type subst =
-+  | SubstString of int * int (* Denotes a substring in the substitution *)
-+  | Backref of int (* nth backreference ($0 is program name!) *)
-+  | Match (* The whole matched string *)
-+  | PreMatch (* The string before the match *)
-+  | PostMatch (* The string after the match *)
-+  | LastParenMatch (* The last matched group *)
-+
-+(* Information on substitution patterns *)
-+type substitution =
-+  string (* The substitution string *)
-+  * int (* Highest group number of backreferences *)
-+  * bool (* Makes use of "LastParenMatch" *)
-+  * subst list (* The list of substitution elements *)
-+
-+(* Only used internally in "subst" *)
-+exception FoundAt of int
-+
-+let zero = Char.code '0'
-+
-+let subst str =
-+  let max_br = ref 0 in
-+  let with_lp = ref false in
-+  let lix = String.length str - 1 in
-+  let rec loop acc n =
-+    if lix < n then acc
-+    else
-+      try
-+        for i = n to lix do
-+          if String.unsafe_get str i = '$' then raise (FoundAt i)
-+        done;
-+        SubstString (n, lix - n + 1) :: acc
-+      with FoundAt i -> (
-+        if i = lix then SubstString (n, lix - n + 1) :: acc
-+        else
-+          let i1 = i + 1 in
-+          let acc = if n = i then acc else SubstString (n, i - n) :: acc in
-+          match String.unsafe_get str i1 with
-+          | '0' .. '9' as c -> (
-+              let subpat_nr = ref (Char.code c - zero) in
-+              try
-+                for j = i1 + 1 to lix do
-+                  let c = String.unsafe_get str j in
-+                  if c >= '0' && c <= '9' then
-+                    subpat_nr := (10 * !subpat_nr) + Char.code c - zero
-+                  else raise (FoundAt j)
-+                done;
-+                max_br := max !subpat_nr !max_br;
-+                Backref !subpat_nr :: acc
-+              with FoundAt j ->
-+                max_br := max !subpat_nr !max_br;
-+                loop (Backref !subpat_nr :: acc) j)
-+          | '!' -> loop acc (i1 + 1)
-+          | '$' -> loop (SubstString (i1, 1) :: acc) (i1 + 1)
-+          | '&' -> loop (Match :: acc) (i1 + 1)
-+          | '`' -> loop (PreMatch :: acc) (i1 + 1)
-+          | '\'' -> loop (PostMatch :: acc) (i1 + 1)
-+          | '+' ->
-+              with_lp := true;
-+              loop (LastParenMatch :: acc) (i1 + 1)
-+          | _ -> loop acc i1)
-+  in
-+  let subst_lst = loop [] 0 in
-+  (str, !max_br, !with_lp, subst_lst)
-+
-+let def_subst = subst ""
-+
-+(* Calculates a list of tuples (str, offset, len) which contain substrings to be
-+   copied on substitutions. Internal use only! *)
-+let calc_trans_lst subgroups2 ovector subj templ subst_lst =
-+  let prefix_len = Array.unsafe_get ovector 0 in
-+  let last = Array.unsafe_get ovector 1 in
-+  let coll ((res_len, trans_lst) as accu) =
-+    let return_lst ((_str, _ix, len) as el) =
-+      if len = 0 then accu else (res_len + len, el :: trans_lst)
-+    in
-+    function
-+    | SubstString (ix, len) -> return_lst (templ, ix, len)
-+    | Backref 0 ->
-+        let prog_name = Sys.argv.(0) in
-+        return_lst (prog_name, 0, String.length prog_name)
-+    | Backref n ->
-+        let offset = n lsl 1 in
-+        let start = Array.unsafe_get ovector offset in
-+        let len = Array.unsafe_get ovector (offset + 1) - start in
-+        return_lst (subj, start, len)
-+    | Match -> return_lst (subj, prefix_len, last - prefix_len)
-+    | PreMatch -> return_lst (subj, 0, prefix_len)
-+    | PostMatch -> return_lst (subj, last, String.length subj - last)
-+    | LastParenMatch ->
-+        let subgroups2_2 = subgroups2 - 2 in
-+        let pos = ref subgroups2_2 in
-+        let ix = ref (Array.unsafe_get ovector subgroups2_2) in
-+        while !ix < 0 do
-+          let pos_2 = !pos - 2 in
-+          pos := pos_2;
-+          ix := Array.unsafe_get ovector pos_2
-+        done;
-+        return_lst (subj, !ix, Array.unsafe_get ovector (!pos + 1) - !ix)
-+  in
-+  List.fold_left coll (0, []) subst_lst
-+
-+let replace ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
-+    ?(itempl = def_subst) ?templ ?callout subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let templ, max_br, with_lp, subst_lst =
-+    match templ with Some str -> subst str | _ -> itempl
-+  in
-+  let subj_len = String.length subj in
-+  if pos < 0 || pos > subj_len then invalid_arg "Pcre2.replace: illegal offset";
-+  let subgroups2, ovector = make_ovector rex in
-+  let nsubs = (subgroups2 lsr 1) - 1 in
-+  if max_br > nsubs then
-+    failwith "Pcre2.replace: backreference denotes nonexistent subpattern";
-+  if with_lp && nsubs = 0 then failwith "Pcre2.replace: no backreferences";
-+  let rec loop full_len trans_lsts cur_pos =
-+    if
-+      cur_pos > subj_len
-+      ||
-+      try
-+        unsafe_pcre2_match iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector
-+          callout;
-+        false
-+      with Not_found -> true
-+    then (
-+      let postfix_len = max (subj_len - cur_pos) 0 in
-+      let left = pos + full_len in
-+      let res = Bytes.create (left + postfix_len) in
-+      bytes_unsafe_blit_string subj 0 res 0 pos;
-+      bytes_unsafe_blit_string subj cur_pos res left postfix_len;
-+      let inner_coll ofs (templ, ix, len) =
-+        bytes_unsafe_blit_string templ ix res ofs len;
-+        ofs + len
-+      in
-+      let coll ofs (res_len, trans_lst) =
-+        let new_ofs = ofs - res_len in
-+        let _ = List.fold_left inner_coll new_ofs trans_lst in
-+        new_ofs
-+      in
-+      let _ = List.fold_left coll left trans_lsts in
-+      Bytes.unsafe_to_string res)
-+    else
-+      let first = Array.unsafe_get ovector 0 in
-+      let len = first - cur_pos in
-+      let ((res_len, _) as trans_lst_el) =
-+        calc_trans_lst subgroups2 ovector subj templ subst_lst
-+      in
-+      let trans_lsts =
-+        if len > 0 then
-+          trans_lst_el :: (len, [ (subj, cur_pos, len) ]) :: trans_lsts
-+        else trans_lst_el :: trans_lsts
-+      in
-+      let full_len = full_len + len + res_len in
-+      let next = first + 1 in
-+      let last = Array.unsafe_get ovector 1 in
-+      if last < next then
-+        if first < subj_len then
-+          let new_trans_lsts =
-+            (1, [ (subj, cur_pos + len, 1) ]) :: trans_lsts
-+          in
-+          loop (full_len + 1) new_trans_lsts next
-+        else loop full_len trans_lsts next
-+      else loop full_len trans_lsts last
-+  in
-+  loop 0 [] pos
-+
-+let qreplace ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
-+    ?(templ = "") ?callout subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let subj_len = String.length subj in
-+  if pos < 0 || pos > subj_len then invalid_arg "Pcre2.qreplace: illegal offset";
-+  let templ_len = String.length templ in
-+  let _, ovector = make_ovector rex in
-+  let rec loop full_len subst_lst cur_pos =
-+    if
-+      cur_pos > subj_len
-+      ||
-+      try
-+        unsafe_pcre2_match iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector
-+          callout;
-+        false
-+      with Not_found -> true
-+    then (
-+      let postfix_len = max (subj_len - cur_pos) 0 in
-+      let left = pos + full_len in
-+      let res = Bytes.create (left + postfix_len) in
-+      bytes_unsafe_blit_string subj 0 res 0 pos;
-+      bytes_unsafe_blit_string subj cur_pos res left postfix_len;
-+      let coll ofs = function
-+        | Some (substr, ix, len) ->
-+            let new_ofs = ofs - len in
-+            bytes_unsafe_blit_string substr ix res new_ofs len;
-+            new_ofs
-+        | None ->
-+            let new_ofs = ofs - templ_len in
-+            bytes_unsafe_blit_string templ 0 res new_ofs templ_len;
-+            new_ofs
-+      in
-+      let _ = List.fold_left coll left subst_lst in
-+      Bytes.unsafe_to_string res)
-+    else
-+      let first = Array.unsafe_get ovector 0 in
-+      let len = first - cur_pos in
-+      let subst_lst =
-+        if len > 0 then None :: Some (subj, cur_pos, len) :: subst_lst
-+        else None :: subst_lst
-+      in
-+      let last = Array.unsafe_get ovector 1 in
-+      let full_len = full_len + len + templ_len in
-+      let next = first + 1 in
-+      if last < next then
-+        if first < subj_len then
-+          loop (full_len + 1) (Some (subj, cur_pos + len, 1) :: subst_lst) next
-+        else loop full_len subst_lst next
-+      else loop full_len subst_lst last
-+  in
-+  loop 0 [] pos
-+
-+let substitute_substrings ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
-+    ?callout ~subst subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let subj_len = String.length subj in
-+  if pos < 0 || pos > subj_len then
-+    invalid_arg "Pcre2.substitute: illegal offset";
-+  let _, ovector = make_ovector rex in
-+  let rec loop full_len subst_lst cur_pos =
-+    if
-+      cur_pos > subj_len
-+      ||
-+      try
-+        unsafe_pcre2_match iflags rex ~pos:cur_pos ~subj_start:0 ~subj ovector
-+          callout;
-+        false
-+      with Not_found -> true
-+    then (
-+      let postfix_len = max (subj_len - cur_pos) 0 in
-+      let left = pos + full_len in
-+      let res = Bytes.create (left + postfix_len) in
-+      bytes_unsafe_blit_string subj 0 res 0 pos;
-+      bytes_unsafe_blit_string subj cur_pos res left postfix_len;
-+      let coll ofs (templ, ix, len) =
-+        let new_ofs = ofs - len in
-+        bytes_unsafe_blit_string templ ix res new_ofs len;
-+        new_ofs
-+      in
-+      let _ = List.fold_left coll left subst_lst in
-+      Bytes.unsafe_to_string res)
-+    else
-+      let first = Array.unsafe_get ovector 0 in
-+      let len = first - cur_pos in
-+      let templ = subst (subj, ovector) in
-+      let templ_len = String.length templ in
-+      let subst_lst =
-+        if len > 0 then
-+          (templ, 0, templ_len) :: (subj, cur_pos, len) :: subst_lst
-+        else (templ, 0, templ_len) :: subst_lst
-+      in
-+      let last = Array.unsafe_get ovector 1 in
-+      let full_len = full_len + len + templ_len in
-+      let next = first + 1 in
-+      if last < next then
-+        if first < subj_len then
-+          loop (full_len + 1) ((subj, cur_pos + len, 1) :: subst_lst) next
-+        else loop full_len subst_lst next
-+      else loop full_len subst_lst last
-+  in
-+  loop 0 [] pos
-+
-+let substitute ?iflags ?flags ?rex ?pat ?pos ?callout ~subst:str_subst subj =
-+  let subst (subj, ovector) =
-+    let first = Array.unsafe_get ovector 0 in
-+    let last = Array.unsafe_get ovector 1 in
-+    str_subst (string_unsafe_sub subj first (last - first))
-+  in
-+  substitute_substrings ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
-+
-+let replace_first ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
-+    ?(itempl = def_subst) ?templ ?callout subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let templ, max_br, with_lp, subst_lst =
-+    match templ with Some str -> subst str | _ -> itempl
-+  in
-+  let subgroups2, ovector = make_ovector rex in
-+  let nsubs = (subgroups2 lsr 1) - 1 in
-+  if max_br > nsubs then
-+    failwith "Pcre2.replace_first: backreference denotes nonexistent subpattern";
-+  if with_lp && nsubs = 0 then failwith "Pcre2.replace_first: no backreferences";
-+  try
-+    unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
-+    let res_len, trans_lst =
-+      calc_trans_lst subgroups2 ovector subj templ subst_lst
-+    in
-+    let first = Array.unsafe_get ovector 0 in
-+    let last = Array.unsafe_get ovector 1 in
-+    let rest = String.length subj - last in
-+    let res = Bytes.create (first + res_len + rest) in
-+    bytes_unsafe_blit_string subj 0 res 0 first;
-+    let coll ofs (templ, ix, len) =
-+      bytes_unsafe_blit_string templ ix res ofs len;
-+      ofs + len
-+    in
-+    let ofs = List.fold_left coll first trans_lst in
-+    bytes_unsafe_blit_string subj last res ofs rest;
-+    Bytes.unsafe_to_string res
-+  with Not_found -> subj
-+
-+let qreplace_first ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0)
-+    ?(templ = "") ?callout subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let _, ovector = make_ovector rex in
-+  try
-+    unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
-+    let first = Array.unsafe_get ovector 0 in
-+    let last = Array.unsafe_get ovector 1 in
-+    let len = String.length templ in
-+    let rest = String.length subj - last in
-+    let postfix_start = first + len in
-+    let res = Bytes.create (postfix_start + rest) in
-+    bytes_unsafe_blit_string subj 0 res 0 first;
-+    bytes_unsafe_blit_string templ 0 res first len;
-+    bytes_unsafe_blit_string subj last res postfix_start rest;
-+    Bytes.unsafe_to_string res
-+  with Not_found -> subj
-+
-+let substitute_substrings_first ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat
-+    ?(pos = 0) ?callout ~subst subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let _, ovector = make_ovector rex in
-+  try
-+    unsafe_pcre2_match iflags rex ~pos ~subj_start:0 ~subj ovector callout;
-+    let subj_len = String.length subj in
-+    let prefix_len = Array.unsafe_get ovector 0 in
-+    let last = Array.unsafe_get ovector 1 in
-+    let templ = subst (subj, ovector) in
-+    let postfix_len = subj_len - last in
-+    let templ_len = String.length templ in
-+    let postfix_start = prefix_len + templ_len in
-+    let res = Bytes.create (postfix_start + postfix_len) in
-+    bytes_unsafe_blit_string subj 0 res 0 prefix_len;
-+    bytes_unsafe_blit_string templ 0 res prefix_len templ_len;
-+    bytes_unsafe_blit_string subj last res postfix_start postfix_len;
-+    Bytes.unsafe_to_string res
-+  with Not_found -> subj
-+
-+let substitute_first ?iflags ?flags ?rex ?pat ?pos ?callout ~subst:str_subst
-+    subj =
-+  let subst (subj, ovector) =
-+    let first = Array.unsafe_get ovector 0 in
-+    let last = Array.unsafe_get ovector 1 in
-+    str_subst (string_unsafe_sub subj first (last - first))
-+  in
-+  substitute_substrings_first ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj
-+
-+(* Splitting *)
-+
-+let internal_psplit flags rex max pos callout subj =
-+  let subj_len = String.length subj in
-+  if subj_len = 0 then []
-+  else if max = 1 then [ subj ]
-+  else
-+    let subgroups2, ovector = make_ovector rex in
-+
-+    (* Adds contents of subgroups to the string accumulator *)
-+    let handle_subgroups strs =
-+      let strs = ref strs in
-+      let i = ref 2 in
-+      while !i < subgroups2 do
-+        let first = Array.unsafe_get ovector !i in
-+        incr i;
-+        let last = Array.unsafe_get ovector !i in
-+        let str =
-+          if first < 0 then "" else string_unsafe_sub subj first (last - first)
-+        in
-+        strs := str :: !strs;
-+        incr i
-+      done;
-+      !strs
-+    in
-+
-+    (* Performs the recursive split *)
-+    let rec loop strs cnt pos prematch =
-+      let len = subj_len - pos in
-+      if len < 0 then strs
-+      else if
-+        (* Checks termination due to max restriction *)
-+        cnt = 0
-+      then
-+        if
-+          prematch
-+          &&
-+          try
-+            unsafe_pcre2_match flags rex ~pos ~subj_start:pos ~subj ovector
-+              callout;
-+            true
-+          with Not_found -> false
-+        then
-+          let last = Array.unsafe_get ovector 1 in
-+          let strs = handle_subgroups strs in
-+          string_unsafe_sub subj last (subj_len - last) :: strs
-+        else string_unsafe_sub subj pos len :: strs
-+          (* Calculates next accumulator state for splitting *)
-+      else if
-+        try
-+          unsafe_pcre2_match flags rex ~pos ~subj_start:pos ~subj ovector
-+            callout;
-+          false
-+        with Not_found -> true
-+      then string_unsafe_sub subj pos len :: strs
-+      else
-+        let first = Array.unsafe_get ovector 0 in
-+        let last = Array.unsafe_get ovector 1 in
-+        if first = pos then
-+          if last = pos then
-+            let strs = if prematch then handle_subgroups strs else strs in
-+            if len = 0 then "" :: strs
-+            else if
-+              try
-+                unsafe_pcre2_match
-+                  (* `ANCHORED | `NOTEMPTY *)
-+                  (Int64.logor flags 0x80000004L)
-+                  rex ~pos ~subj_start:pos ~subj ovector callout;
-+                true
-+              with Not_found -> false
-+            then
-+              let new_strs = handle_subgroups ("" :: strs) in
-+              loop new_strs (cnt - 1) (Array.unsafe_get ovector 1) false
-+            else
-+              let new_strs = string_unsafe_sub subj pos 1 :: strs in
-+              loop new_strs (cnt - 1) (pos + 1) true
-+          else if prematch then loop (handle_subgroups strs) cnt last false
-+          else loop (handle_subgroups ("" :: strs)) (cnt - 1) last false
-+        else
-+          let new_strs = string_unsafe_sub subj pos (first - pos) :: strs in
-+          loop (handle_subgroups new_strs) (cnt - 1) last false
-+    in
-+    loop [] (max - 1) pos false
-+
-+let rec strip_all_empty = function "" :: t -> strip_all_empty t | l -> l
-+
-+external isspace : char -> bool = "pcre2_isspace_stub" [@@noalloc]
-+
-+let rec find_no_space ix len str =
-+  if ix = len || not (isspace (String.unsafe_get str ix)) then ix
-+  else find_no_space (ix + 1) len str
-+
-+let split ?(iflags = 0L) ?flags ?rex ?pat ?(pos = 0) ?(max = 0) ?callout subj =
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let res =
-+    match (pat, rex) with
-+    | Some str, _ -> internal_psplit iflags (regexp str) max pos callout subj
-+    | _, Some rex -> internal_psplit iflags rex max pos callout subj
-+    | _ ->
-+        (* special case for Perl-splitting semantics *)
-+        let len = String.length subj in
-+        if pos > len || pos < 0 then failwith "Pcre2.split: illegal offset";
-+        let new_pos = find_no_space pos len subj in
-+        internal_psplit iflags def_rex max new_pos callout subj
-+  in
-+  List.rev (if max = 0 then strip_all_empty res else res)
-+
-+let asplit ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj =
-+  Array.of_list (split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj)
-+
-+(* Full splitting *)
-+
-+type split_result =
-+  | Text of string
-+  | Delim of string
-+  | Group of int * string
-+  | NoGroup
-+
-+let rec strip_all_empty_full = function
-+  | Delim _ :: rest -> strip_all_empty_full rest
-+  | l -> l
-+
-+let full_split ?(iflags = 0L) ?flags ?(rex = def_rex) ?pat ?(pos = 0) ?(max = 0)
-+    ?callout subj =
-+  let rex = match pat with Some str -> regexp str | _ -> rex in
-+  let iflags = match flags with Some flags -> rflags flags | _ -> iflags in
-+  let subj_len = String.length subj in
-+  if subj_len = 0 then []
-+  else if max = 1 then [ Text subj ]
-+  else
-+    let subgroups2, ovector = make_ovector rex in
-+
-+    (* Adds contents of subgroups to the string accumulator *)
-+    let handle_subgroups strs =
-+      let strs = ref strs in
-+      let i = ref 2 in
-+      while !i < subgroups2 do
-+        let group_nr = !i lsr 1 in
-+        let first = Array.unsafe_get ovector !i in
-+        incr i;
-+        let last = Array.unsafe_get ovector !i in
-+        let str =
-+          if first < 0 then NoGroup
-+          else
-+            let group_str = string_unsafe_sub subj first (last - first) in
-+            Group (group_nr, group_str)
-+        in
-+        strs := str :: !strs;
-+        incr i
-+      done;
-+      !strs
-+    in
-+
-+    (* Performs the recursive split *)
-+    let rec loop strs cnt pos prematch =
-+      let len = subj_len - pos in
-+      if len < 0 then strs
-+      else if
-+        (* Checks termination due to max restriction *)
-+        cnt = 0
-+      then
-+        if
-+          prematch
-+          &&
-+          try
-+            unsafe_pcre2_match iflags rex ~pos ~subj_start:pos ~subj ovector
-+              callout;
-+            true
-+          with Not_found -> false
-+        then
-+          let first = Array.unsafe_get ovector 0 in
-+          let last = Array.unsafe_get ovector 1 in
-+          let delim = Delim (string_unsafe_sub subj first (last - first)) in
-+          Text (string_unsafe_sub subj last (subj_len - last))
-+          :: handle_subgroups (delim :: strs)
-+        else if len = 0 then strs
-+        else Text (string_unsafe_sub subj pos len) :: strs
-+          (* Calculates next accumulator state for splitting *)
-+      else if
-+        try
-+          unsafe_pcre2_match iflags rex ~pos ~subj_start:pos ~subj ovector
-+            callout;
-+          false
-+        with Not_found -> true
-+      then
-+        if len = 0 then strs else Text (string_unsafe_sub subj pos len) :: strs
-+      else
-+        let first = Array.unsafe_get ovector 0 in
-+        let last = Array.unsafe_get ovector 1 in
-+        if first = pos then
-+          if last = pos then
-+            if len = 0 then handle_subgroups (Delim "" :: strs)
-+            else
-+              let empty_groups = handle_subgroups [] in
-+              if
-+                try
-+                  unsafe_pcre2_match
-+                    (* `ANCHORED | `NOTEMPTY *)
-+                    (Int64.logor iflags 0x80000004L)
-+                    rex ~pos ~subj_start:pos ~subj ovector callout;
-+                  true
-+                with Not_found -> false
-+              then
-+                let first = Array.unsafe_get ovector 0 in
-+                let last = Array.unsafe_get ovector 1 in
-+                let delim =
-+                  Delim (string_unsafe_sub subj first (last - first))
-+                in
-+                let new_strs =
-+                  let tmp_strs =
-+                    if prematch then strs else empty_groups @ (Delim "" :: strs)
-+                  in
-+                  handle_subgroups (delim :: tmp_strs)
-+                in
-+                loop new_strs (cnt - 1) last false
-+              else
-+                let new_strs =
-+                  (Text (string_unsafe_sub subj pos 1) :: empty_groups)
-+                  @ (Delim "" :: strs)
-+                in
-+                loop new_strs (cnt - 1) (pos + 1) true
-+          else
-+            let delim = Delim (string_unsafe_sub subj first (last - first)) in
-+            loop (handle_subgroups (delim :: strs)) cnt last false
-+        else
-+          let delim = Delim (string_unsafe_sub subj first (last - first)) in
-+          let pre_strs =
-+            Text (string_unsafe_sub subj pos (first - pos)) :: strs
-+          in
-+          loop (handle_subgroups (delim :: pre_strs)) (cnt - 1) last false
-+    in
-+    let res = loop [] (max - 1) pos true in
-+    List.rev (if max = 0 then strip_all_empty_full res else res)
-+
-+(* Additional convenience functions useful in combination with this library *)
-+
-+let foreach_line ?(ic = stdin) f =
-+  try
-+    while true do
-+      f (input_line ic)
-+    done
-+  with End_of_file -> ()
-+
-+let foreach_file filenames f =
-+  let do_with_file filename =
-+    let file = open_in filename in
-+    try
-+      f filename file;
-+      close_in file
-+    with exn ->
-+      close_in file;
-+      raise exn
-+  in
-+  List.iter do_with_file filenames
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/pcre2.mli b/bundles/pcre2/pcre2-ocaml/lib/pcre2.mli
-new file mode 100644
-index 000000000..a61bcd857
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/pcre2.mli
-@@ -0,0 +1,1068 @@
-+(* PCRE2-OCAML - Perl Compatibility Regular Expressions for OCaml
-+
-+   Copyright © 1999- Markus Mottl <markus.mottl@gmail.com>
-+
-+   This library is free software; you can redistribute it and/or modify it under
-+   the terms of the GNU Lesser General Public License as published by the Free
-+   Software Foundation; either version 2.1 of the License, or (at your option)
-+   any later version.
-+
-+   This library 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 Lesser General Public License for more
-+   details.
-+
-+   You should have received a copy of the GNU Lesser General Public License
-+   along with this library; if not, write to the Free Software Foundation, Inc.,
-+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *)
-+
-+(** Perl Compatibility Regular Expressions for OCaml
-+
-+    {e %%VERSION%% - {{:%%PKG_HOMEPAGE%%} homepage}} *)
-+
-+(** {1 Exceptions} *)
-+
-+type error =
-+  | Partial  (** String only matched the pattern partially *)
-+  | BadPattern of string * int
-+      (** [BadPattern (msg, pos)] regular expression is malformed. The reason is
-+          in [msg], the position of the error in the pattern in [pos]. *)
-+  | BadUTF  (** UTF string being matched is invalid *)
-+  | BadUTFOffset
-+      (** Gets raised when a UTF string being matched with offset is invalid. *)
-+  | MatchLimit
-+      (** Maximum allowed number of match attempts with backtracking or
-+          recursion is reached during matching. ALL FUNCTIONS CALLING THE
-+          MATCHING ENGINE MAY RAISE IT!!! *)
-+  | DepthLimit
-+  | WorkspaceSize
-+      (** Raised by {!pcre2_dfa_match} when the provided workspace array is too
-+          small. See documention on {!pcre2_dfa_match} for details on workspace
-+          array sizing. *)
-+  | InternalError of string
-+      (** [InternalError msg] C-library exhibits unknown/undefined behaviour.
-+          The reason is in [msg]. *)
-+
-+exception Error of error
-+(** Exception indicating PCRE errors. *)
-+
-+exception Backtrack
-+(** [Backtrack] used in callout functions to force backtracking. *)
-+
-+exception Regexp_or of string * error
-+(** [Regexp_or (pat, error)] gets raised for sub-pattern [pat] by [regexp_or] if
-+    it failed to compile. *)
-+
-+(** {1 Compilation and runtime flags and their conversion functions} *)
-+
-+type icflag
-+(** Internal representation of compilation flags *)
-+
-+and irflag
-+(** Internal representation of runtime flags *)
-+
-+and cflag =
-+  [ `ALLOW_EMPTY_CLASS  (** Allow empty classes *)
-+  | `ALT_BSUX  (** Alternative handling of \u, \U, and \x *)
-+  | `ALT_CIRCUMFLEX  (** Alternative handling of ^ in multiline mode *)
-+  | `ALT_VERBNAMES  (** Process backslashes in verb names *)
-+  | `ANCHORED  (** Pattern matches only at start of string *)
-+  | `AUTO_CALLOUT
-+    (** Automatically inserts callouts with id 255 before each pattern item *)
-+  | `CASELESS  (** Case insensitive matching *)
-+  | `DOLLAR_ENDONLY  (** '$' in pattern matches only at end of string *)
-+  | `DOTALL  (** '.' matches all characters (newlines, too) *)
-+  | `DUPNAMES  (** Allow duplicate names for subpatterns *)
-+  | `ENDANCHORED  (** Pattern can match only at end of subject *)
-+  | `EXTENDED
-+    (** Ignores whitespace and PERL-comments. Behaves like the '/x'-option in
-+        PERL *)
-+  | `EXTENDED_MORE
-+  | `FIRSTLINE  (** Unanchored patterns must match before/at first NL *)
-+  | `LITERAL  (** Pattern characters are all literal *)
-+  | `MATCH_INVALID_UTF  (** Enable support for matching invalid UTF *)
-+  | `MATCH_UNSET_BACKREF  (** Match unset backreferences *)
-+  | `MULTILINE
-+    (** '^' and '$' match before/after newlines, not just at the beginning/end
-+        of a string *)
-+  | `NEVER_BACKSLASH_C  (** Lock out the use of \C in patterns *)
-+  | `NEVER_UCP  (** Lock out UCP, e.g. via (\*UCP) *)
-+  | `NEVER_UTF  (** Lock out UTF, e.g. via (\*UTF) *)
-+  | `NO_AUTO_CAPTURE  (** Disables the use of numbered capturing parentheses *)
-+  | `NO_AUTO_POSSESS  (** Disable auto-possessification *)
-+  | `NO_DOTSTAR_ANCHOR  (** Disable automatic anchoring for .* *)
-+  | `NO_START_OPTIMIZE  (** Disable match-time start optimizations *)
-+  | `NO_UTF_CHECK
-+    (** Do not check the pattern for UTF validity (only relevant if UTF is set)
-+        WARNING: with this flag enabled, invalid UTF strings may cause a crash,
-+        loop, or give incorrect results *)
-+  | `UCP  (** Use Unicode properties for \d, \w, etc. *)
-+  | `UNGREEDY  (** Quantifiers not greedy anymore, only if followed by '?' *)
-+  | `USE_OFFSET_LIMIT  (** Enable offset limit for unanchored matching *)
-+  | `UTF  (** Treat pattern and subjects as UTF strings *) ]
-+(** Compilation flags *)
-+
-+val cflags : cflag list -> icflag
-+(** [cflags cflag_list] converts a list of compilation flags to their internal
-+    representation. *)
-+
-+val cflag_list : icflag -> cflag list
-+(** [cflag_list cflags] converts internal representation of compilation flags to
-+    a list. *)
-+
-+type rflag =
-+  [ `ANCHORED  (** Match only at the first position *)
-+  | `COPY_MATCHED_SUBJECT  (** On success, make a private subject copy *)
-+  | `DFA_RESTART
-+    (** Causes matching to proceed presuming the subject string is further to
-+        one partially matched previously using the same int-array working set.
-+        May only be used with {!pcre2_dfa_match} or {!unsafe_pcre2_dfa_match},
-+        and should always be paired with [`PARTIAL]. *)
-+  | `DFA_SHORTEST  (** Return only the shortest match *)
-+  | `ENDANCHORED  (** Pattern can match only at end of subject *)
-+  | `NOTBOL  (** Beginning of string is not treated as beginning of line *)
-+  | `NOTEOL  (** End of string is not treated as end of line *)
-+  | `NOTEMPTY  (** An empty string is not a valid match *)
-+  | `NOTEMPTY_ATSTART
-+    (** An empty string at the start of the subject is not a valid match *)
-+  | `NO_JIT  (** Do not use JIT matching *)
-+  | `NO_UTF_CHECK
-+    (** Do not check the subject for UTF validity (only relevant if PCRE2_UTF
-+        was set at compile time) *)
-+  | `PARTIAL_HARD
-+    (** Throw Pcre2.Partial for a partial match even if there is a full match *)
-+  | `PARTIAL_SOFT
-+    (** Throw Pcre2.Partial for a partial match if no full matches are found *)
-+  ]
-+(** Runtime flags *)
-+
-+val rflags : rflag list -> irflag
-+(** [rflags rflag_list] converts a list of runtime flags to their internal
-+    representation. *)
-+
-+val rflag_list : irflag -> rflag list
-+(** [rflag_list rflags] converts internal representation of runtime flags to a
-+    list. *)
-+
-+(** {1 Information on the PCRE2-configuration (build-time options)} *)
-+
-+(** Version information *)
-+val version : string
-+(** Version of the PCRE2-C-library *)
-+
-+val config_unicode : bool
-+(** Indicates whether unicode support is enabled *)
-+
-+val config_newline : char
-+(** Character used as newline *)
-+
-+val config_link_size : int
-+(** Number of bytes used for internal linkage of regular expressions *)
-+
-+val config_match_limit : int
-+(** Default limit for calls to internal matching function *)
-+
-+val config_depth_limit : int
-+(** Default limit for depth of nested backtracking *)
-+
-+val config_stackrecurse : bool
-+(** Indicates use of stack recursion in matching function *)
-+
-+(** {1 Information on patterns} *)
-+
-+type firstcodeunit_info =
-+  [ `Char of char  (** Fixed first character *)
-+  | `Start_only  (** Pattern matches at beginning and end of newlines *)
-+  | `ANCHORED  (** Pattern is anchored *) ]
-+(** Information on matching of "first chars" in patterns *)
-+
-+type regexp
-+(** Compiled regular expressions *)
-+
-+val options : regexp -> icflag
-+(** [options regexp]
-+
-+    @return compilation flags of [regexp]. *)
-+
-+val size : regexp -> int
-+(** [size regexp]
-+
-+    @return memory size of [regexp]. *)
-+
-+val capturecount : regexp -> int
-+(** [capturecount regexp]
-+
-+    @return number of capturing subpatterns in [regexp]. *)
-+
-+val backrefmax : regexp -> int
-+(** [backrefmax regexp]
-+
-+    @return number of highest backreference in [regexp]. *)
-+
-+val namecount : regexp -> int
-+(** [namecount regexp]
-+
-+    @return number of named subpatterns in [regexp]. *)
-+
-+val nameentrysize : regexp -> int
-+(** [nameentrysize regexp]
-+
-+    @return size of longest name of named subpatterns in [regexp] + 3. *)
-+
-+val names : regexp -> string array
-+(** [names regex]
-+
-+    @return array of names of named substrings in [regexp]. *)
-+
-+val firstcodeunit : regexp -> firstcodeunit_info
-+(** [firstcodeunit regexp]
-+
-+    @return firstcodeunit info on [regexp]. *)
-+
-+val lastcodeunit : regexp -> char option
-+(** [lastcodeunit regexp]
-+
-+    @return
-+      some last matching character of [regexp] if available, [None] otherwise.
-+*)
-+
-+val get_stringnumber : regexp -> string -> int
-+(** [get_stringnumber rex name]
-+
-+    @return
-+      the index of the named substring [name] in regular expression [rex]. This
-+      index can then be used with [get_substring].
-+
-+    @raise Invalid_arg if there is no such named substring. *)
-+
-+(* val get_match_limit : regexp -> int option *)
-+(** [get_match_limit rex]
-+
-+    @return some match limit of regular expression [rex] or [None]. *)
-+
-+(* val get_depth_limit : regexp -> int option *)
-+(** [get_depth_limit rex]
-+
-+    @return some depth limit of regular expression [rex] or [None]. *)
-+
-+(** {1 Compilation of patterns} *)
-+
-+type chtables
-+(** Alternative set of char tables for pattern matching *)
-+
-+val maketables : unit -> chtables
-+(** Generates new set of char tables for the current locale. *)
-+
-+val regexp :
-+  ?limit:
-+    (* ?jit_compile : bool -> *)
-+    int ->
-+  ?depth_limit:int ->
-+  ?iflags:icflag ->
-+  ?flags:cflag list ->
-+  ?chtables:chtables ->
-+  string ->
-+  regexp
-+(** [regexp ?limit ?depth_limit ?iflags ?flags ?chtables pattern] compiles
-+    [pattern] with [flags] when given, with [iflags] otherwise, and with char
-+    tables [chtables]. If [limit] is specified, this sets a limit to the amount
-+    of recursion and backtracking (only lower than the builtin default!). If
-+    this limit is exceeded, [MatchLimit] will be raised during matching.
-+
-+    @param limit default = no extra limit other than default
-+    @param depth_limit default = no extra depth_limit other than default
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param chtables default = builtin char tables
-+
-+    @return the regular expression.
-+
-+    For detailed documentation on how you can specify PERL-style regular
-+    expressions (= patterns), please consult the PCRE2-documentation ("man
-+    pcre2pattern") or PERL-manuals.
-+    @see <http://www.perl.com> www.perl.com *)
-+
-+val regexp_or :
-+  ?limit:
-+    (* ?jit_compile : bool -> *)
-+    int ->
-+  ?depth_limit:int ->
-+  ?iflags:icflag ->
-+  ?flags:cflag list ->
-+  ?chtables:chtables ->
-+  string list ->
-+  regexp
-+(** [regexp_or ?limit ?depth_limit ?iflags ?flags ?chtables patterns] like
-+    {!val-regexp}, but combines [patterns] as alternatives (or-patterns) into
-+    one regular expression. *)
-+
-+val quote : string -> string
-+(** [quote str]
-+
-+    @return the quoted string of [str]. *)
-+
-+(** {1 Subpattern extraction} *)
-+
-+type substrings
-+(** Information on substrings after pattern matching *)
-+
-+val get_subject : substrings -> string
-+(** [get_subject substrings]
-+
-+    @return the subject string of [substrings]. *)
-+
-+val num_of_subs : substrings -> int
-+(** [num_of_subs substrings]
-+
-+    @return number of strings in [substrings] (whole match inclusive). *)
-+
-+val get_substring : substrings -> int -> string
-+(** [get_substring substrings n]
-+
-+    @return the [n]th substring (0 is whole match) of [substrings].
-+
-+    @raise Invalid_argument
-+      if [n] is not in the range of the number of substrings.
-+    @raise Not_found
-+      if the corresponding subpattern did not capture a substring. *)
-+
-+val get_substring_ofs : substrings -> int -> int * int
-+(** [get_substring_ofs substrings n]
-+
-+    @return
-+      the offset tuple of the [n]th substring of [substrings] (0 is whole
-+      match).
-+
-+    @raise Invalid_argument
-+      if [n] is not in the range of the number of substrings.
-+    @raise Not_found
-+      if the corresponding subpattern did not capture a substring. *)
-+
-+val get_substrings : ?full_match:bool -> substrings -> string array
-+(** [get_substrings ?full_match substrings]
-+
-+    @return
-+      the array of substrings in [substrings]. It includes the full match at
-+      index 0 when [full_match] is [true], the captured substrings only when it
-+      is [false]. If a subpattern did not capture a substring, the empty string
-+      is returned in the corresponding position instead.
-+
-+    @param full_match default = true *)
-+
-+val get_opt_substrings : ?full_match:bool -> substrings -> string option array
-+(** [get_opt_substrings ?full_match substrings]
-+
-+    @return
-+      the array of optional substrings in [substrings]. It includes
-+      [Some full_match_str] at index 0 when [full_match] is [true],
-+      [Some captured_substrings] only when it is [false]. If a subpattern did
-+      not capture a substring, [None] is returned in the corresponding position
-+      instead.
-+
-+    @param full_match default = true *)
-+
-+val get_named_substring : regexp -> string -> substrings -> string
-+(** [get_named_substring rex name substrings]
-+
-+    @return
-+      the named substring [name] in regular expression [rex] and [substrings].
-+
-+    @raise Invalid_argument if there is no such named substring.
-+    @raise Not_found
-+      if the corresponding subpattern did not capture a substring. *)
-+
-+val get_named_substring_ofs : regexp -> string -> substrings -> int * int
-+(** [get_named_substring_ofs rex name substrings]
-+
-+    @return
-+      the offset tuple of the named substring [name] in regular expression [rex]
-+      and [substrings].
-+
-+    @raise Invalid_argument if there is no such named substring.
-+    @raise Not_found
-+      if the corresponding subpattern did not capture a substring. *)
-+
-+(** {1 Callouts} *)
-+
-+type callout_data = {
-+  callout_number : int;  (** Callout number *)
-+  substrings : substrings;  (** Substrings matched so far *)
-+  start_match : int;  (** Subject start offset of current match attempt *)
-+  current_position : int;  (** Subject offset of current match pointer *)
-+  capture_top : int;  (** Number of the highest captured substring so far *)
-+  capture_last : int;  (** Number of the most recently captured substring *)
-+  pattern_position : int;  (** Offset of next match item in pattern string *)
-+  next_item_length : int;  (** Length of next match item in pattern string *)
-+}
-+
-+(** Type of callout functions *)
-+type callout = callout_data -> unit
-+(** Callouts are referred to in patterns as "(?Cn)" where "n" is a
-+    [callout_number] ranging from 0 to 255. Substrings captured so far are
-+    accessible as usual via [substrings]. You will have to consider
-+    [capture_top] and [capture_last] to know about the current state of valid
-+    substrings.
-+
-+    By raising exception [Backtrack] within a callout function, the user can
-+    force the pattern matching engine to backtrack to other possible solutions.
-+    Other exceptions will terminate matching immediately and return control to
-+    OCaml. *)
-+
-+(** {1 Matching of patterns and subpattern extraction} *)
-+
-+val pcre2_match :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  string ->
-+  int array
-+(** [pcre2_match ?iflags ?flags ?rex ?pat ?pos ?callout subj]
-+
-+    @return
-+      an array of offsets that describe the position of matched subpatterns in
-+      the string [subj] starting at position [pos] with pattern [pat] when
-+      given, regular expression [rex] otherwise. The array also contains
-+      additional workspace needed by the match engine. Uses [flags] when given,
-+      the precompiled [iflags] otherwise. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val pcre2_dfa_match :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  ?workspace:int array ->
-+  string ->
-+  int array
-+(** [pcre2_dfa_match ?iflags ?flags ?rex ?pat ?pos ?callout ?workspace subj]
-+    invokes the "alternative" DFA matching function.
-+
-+    @return
-+      an array of offsets that describe the position of matched subpatterns in
-+      the string [subj] starting at position [pos] with pattern [pat] when
-+      given, regular expression [rex] otherwise. The array also contains
-+      additional workspace needed by the match engine. Uses [flags] when given,
-+      the precompiled [iflags] otherwise. Requires a sufficiently-large
-+      [workspace] array. Callouts are handled by [callout].
-+
-+    Note that the returned array of offsets are quite different from those
-+    returned by {!pcre2_match} et al. The motivating use case for the DFA match
-+    function is to be able to restart a partial match with N additional input
-+    segments. Because the match function/workspace does not store segments seen
-+    previously, the offsets returned when a match completes will refer only to
-+    the matching portion of the last subject string provided. Thus, returned
-+    offsets from this function should not be used to support extracting captured
-+    submatches. If you need to capture submatches from a series of inputs
-+    incrementally matched with this function, you'll need to concatenate those
-+    inputs that yield a successful match here and re-run the same pattern
-+    against that single subject string.
-+
-+    Aside from an absolute minimum of [20], PCRE does not provide any guidance
-+    regarding the size of workspace array needed by any given pattern.
-+    Therefore, it is wise to appropriately handle the possible [WorkspaceSize]
-+    error. If raised, you can allocate a new, larger workspace array and begin
-+    the DFA matching process again.
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts
-+    @param workspace default = fresh array of length [20]
-+
-+    @raise Not_found if the pattern match has failed
-+    @raise Error
-+      Partial if the pattern has matched partially; a subsequent exec call with
-+      the same pattern and workspace (adding the [DFA_RESTART] flag) be made to
-+      either further advance or complete the partial match.
-+    @raise Error
-+      WorkspaceSize if the workspace array is too small to accommodate the DFA
-+      state required by the supplied pattern *)
-+
-+val exec :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  string ->
-+  substrings
-+(** [exec ?iflags ?flags ?rex ?pat ?pos ?callout subj]
-+
-+    @return
-+      substring information on string [subj] starting at position [pos] with
-+      pattern [pat] when given, regular expression [rex] otherwise. Uses [flags]
-+      when given, the precompiled [iflags] otherwise. Callouts are handled by
-+      [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val exec_all :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  string ->
-+  substrings array
-+(** [exec_all ?iflags ?flags ?rex ?pat ?pos ?callout subj]
-+
-+    @return
-+      an array of substring information of all matching substrings in string
-+      [subj] starting at position [pos] with pattern [pat] when given, regular
-+      expression [rex] otherwise. Uses [flags] when given, the precompiled
-+      [iflags] otherwise. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val next_match :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  substrings ->
-+  substrings
-+(** [next_match ?iflags ?flags ?rex ?pat ?pos ?callout substrs]
-+
-+    @return
-+      substring information on the match that follows on the last match denoted
-+      by [substrs], jumping over [pos] characters (also backwards!), using
-+      pattern [pat] when given, regular expression [rex] otherwise. Uses [flags]
-+      when given, the precompiled [iflags] otherwise. Callouts are handled by
-+      [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match.
-+    @raise Invalid_arg
-+      if [pos] let matching start outside of the subject string. *)
-+
-+val extract :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?full_match:bool ->
-+  ?callout:callout ->
-+  string ->
-+  string array
-+(** [extract ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
-+
-+    @return
-+      the array of substrings that match [subj] starting at position [pos],
-+      using pattern [pat] when given, regular expression [rex] otherwise. Uses
-+      [flags] when given, the precompiled [iflags] otherwise. It includes the
-+      full match at index 0 when [full_match] is [true], the captured substrings
-+      only when it is [false]. Callouts are handled by [callout]. If a
-+      subpattern did not capture a substring, the empty string is returned in
-+      the corresponding position instead.
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param full_match default = true
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val extract_opt :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?full_match:bool ->
-+  ?callout:callout ->
-+  string ->
-+  string option array
-+(** [extract_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
-+
-+    @return
-+      the array of optional substrings that match [subj] starting at position
-+      [pos], using pattern [pat] when given, regular expression [rex] otherwise.
-+      Uses [flags] when given, the precompiled [iflags] otherwise. It includes
-+      [Some full_match_str] at index 0 when [full_match] is [true],
-+      [Some captured-substrings] only when it is [false]. Callouts are handled
-+      by [callout]. If a subpattern did not capture a substring, [None] is
-+      returned in the corresponding position instead.
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param full_match default = true
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val extract_all :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?full_match:bool ->
-+  ?callout:callout ->
-+  string ->
-+  string array array
-+(** [extract_all ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
-+
-+    @return
-+      an array of arrays of all matching substrings that match [subj] starting
-+      at position [pos], using pattern [pat] when given, regular expression
-+      [rex] otherwise. Uses [flags] when given, the precompiled [iflags]
-+      otherwise. It includes the full match at index 0 of the extracted string
-+      arrays when [full_match] is [true], the captured substrings only when it
-+      is [false]. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param full_match default = true
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val extract_all_opt :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?full_match:bool ->
-+  ?callout:callout ->
-+  string ->
-+  string option array array
-+(** [extract_all_opt ?iflags ?flags ?rex ?pat ?pos ?full_match ?callout subj]
-+
-+    @return
-+      an array of arrays of all optional matching substrings that match [subj]
-+      starting at position [pos], using pattern [pat] when given, regular
-+      expression [rex] otherwise. Uses [flags] when given, the precompiled
-+      [iflags] otherwise. It includes [Some full_match_str] at index 0 of the
-+      extracted string arrays when [full_match] is [true],
-+      [Some captured_substrings] only when it is [false]. Callouts are handled
-+      by [callout]. If a subpattern did not capture a substring, [None] is
-+      returned in the corresponding position instead.
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param full_match default = true
-+    @param callout default = ignore callouts
-+
-+    @raise Not_found if pattern does not match. *)
-+
-+val pmatch :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  string ->
-+  bool
-+(** [pmatch ?iflags ?flags ?rex ?pat ?pos ?callout subj]
-+
-+    @return
-+      [true] if [subj] is matched by pattern [pat] when given, regular
-+      expression [rex] otherwise, starting at position [pos]. Uses [flags] when
-+      given, the precompiled [iflags] otherwise. Callouts are handled by
-+      [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts *)
-+
-+(** {1 String substitution} *)
-+
-+type substitution
-+(** Information on substitution patterns *)
-+
-+val subst : string -> substitution
-+(** [subst str] converts the string [str] representing a substitution pattern to
-+    the internal representation
-+
-+    The contents of the substitution string [str] can be normal text mixed with
-+    any of the following (mostly as in PERL):
-+
-+    - {e $\[0-9\]+} - a "$" immediately followed by an arbitrary number. "$0"
-+      stands for the name of the executable, any other number for the n-th
-+      backreference.
-+    - {e $&} - the whole matched pattern
-+    - {e $`} - the text before the match
-+    - {e $'} - the text after the match
-+    - {e $+} - the last group that matched
-+    - {e $$} - a single "$"
-+    - {e $!} - delimiter which does not appear in the substitution. Can be used
-+      to part "$[0-9]+" from an immediately following other number. *)
-+
-+val replace :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?itempl:substitution ->
-+  ?templ:string ->
-+  ?callout:callout ->
-+  string ->
-+  string
-+(** [replace ?iflags ?flags ?rex ?pat ?pos ?itempl ?templ ?callout subj]
-+    replaces all substrings of [subj] matching pattern [pat] when given, regular
-+    expression [rex] otherwise, starting at position [pos] with the substitution
-+    string [templ] when given, [itempl] otherwise. Uses [flags] when given, the
-+    precompiled [iflags] otherwise. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param itempl default = empty string
-+    @param templ default = ignored
-+    @param callout default = ignore callouts
-+
-+    @raise Failure if there are backreferences to nonexistent subpatterns. *)
-+
-+val qreplace :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?templ:string ->
-+  ?callout:callout ->
-+  string ->
-+  string
-+(** [qreplace ?iflags ?flags ?rex ?pat ?pos ?templ ?callout subj] replaces all
-+    substrings of [subj] matching pattern [pat] when given, regular expression
-+    [rex] otherwise, starting at position [pos] with the string [templ]. Uses
-+    [flags] when given, the precompiled [iflags] otherwise. Callouts are handled
-+    by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param templ default = ignored
-+    @param callout default = ignore callouts *)
-+
-+val substitute_substrings :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  subst:(substrings -> string) ->
-+  string ->
-+  string
-+(** [substitute_substrings ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj]
-+    replaces all substrings of [subj] matching pattern [pat] when given, regular
-+    expression [rex] otherwise, starting at position [pos] with the result of
-+    function [subst] applied to the substrings of the match. Uses [flags] when
-+    given, the precompiled [iflags] otherwise. Callouts are handled by
-+    [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts *)
-+
-+val substitute :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  subst:(string -> string) ->
-+  string ->
-+  string
-+(** [substitute ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj] replaces all
-+    substrings of [subj] matching pattern [pat] when given, regular expression
-+    [rex] otherwise, starting at position [pos] with the result of function
-+    [subst] applied to the match. Uses [flags] when given, the precompiled
-+    [iflags] otherwise. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts *)
-+
-+val replace_first :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?itempl:substitution ->
-+  ?templ:string ->
-+  ?callout:callout ->
-+  string ->
-+  string
-+(** [replace_first ?iflags ?flags ?rex ?pat ?pos ?itempl ?templ ?callout subj]
-+    replaces the first substring of [subj] matching pattern [pat] when given,
-+    regular expression [rex] otherwise, starting at position [pos] with the
-+    substitution string [templ] when given, [itempl] otherwise. Uses [flags]
-+    when given, the precompiled [iflags] otherwise. Callouts are handled by
-+    [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param itempl default = empty string
-+    @param templ default = ignored
-+    @param callout default = ignore callouts
-+
-+    @raise Failure if there are backreferences to nonexistent subpatterns. *)
-+
-+val qreplace_first :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?templ:string ->
-+  ?callout:callout ->
-+  string ->
-+  string
-+(** [qreplace_first ?iflags ?flags ?rex ?pat ?pos ?templ ?callout subj] replaces
-+    the first substring of [subj] matching pattern [pat] when given, regular
-+    expression [rex] otherwise, starting at position [pos] with the string
-+    [templ]. Uses [flags] when given, the precompiled [iflags] otherwise.
-+    Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param templ default = ignored
-+    @param callout default = ignore callouts *)
-+
-+val substitute_substrings_first :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  subst:(substrings -> string) ->
-+  string ->
-+  string
-+(** [substitute_substrings_first ?iflags ?flags ?rex ?pat ?pos ?callout ~subst
-+     subj] replaces the first substring of [subj] matching pattern [pat] when
-+    given, regular expression [rex] otherwise, starting at position [pos] with
-+    the result of function [subst] applied to the substrings of the match. Uses
-+    [flags] when given, the precompiled [iflags] otherwise. Callouts are handled
-+    by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts *)
-+
-+val substitute_first :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?callout:callout ->
-+  subst:(string -> string) ->
-+  string ->
-+  string
-+(** [substitute_first ?iflags ?flags ?rex ?pat ?pos ?callout ~subst subj]
-+    replaces the first substring of [subj] matching pattern [pat] when given,
-+    regular expression [rex] otherwise, starting at position [pos] with the
-+    result of function [subst] applied to the match. Uses [flags] when given,
-+    the precompiled [iflags] otherwise. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param callout default = ignore callouts *)
-+
-+(** {1 Splitting} *)
-+
-+val split :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?max:int ->
-+  ?callout:callout ->
-+  string ->
-+  string list
-+(** [split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj] splits [subj] into
-+    a list of at most [max] strings, using as delimiter pattern [pat] when
-+    given, regular expression [rex] otherwise, starting at position [pos]. Uses
-+    [flags] when given, the precompiled [iflags] otherwise. If [max] is zero,
-+    trailing empty fields are stripped. If it is negative, it is treated as
-+    arbitrarily large. If neither [pat] nor [rex] are specified, leading
-+    whitespace will be stripped! Should behave exactly as in PERL. Callouts are
-+    handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param max default = 0
-+    @param callout default = ignore callouts *)
-+
-+val asplit :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?max:int ->
-+  ?callout:callout ->
-+  string ->
-+  string array
-+(** [asplit ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj] same as
-+    {!Pcre2.split} but return an array instead of a list. *)
-+
-+(** Result of a {!Pcre2.full_split} *)
-+type split_result =
-+  | Text of string  (** Text part of split string *)
-+  | Delim of string  (** Delimiter part of split string *)
-+  | Group of int * string
-+      (** Subgroup of matched delimiter (subgroup_nr, subgroup_str) *)
-+  | NoGroup  (** Unmatched subgroup *)
-+
-+val full_split :
-+  ?iflags:irflag ->
-+  ?flags:rflag list ->
-+  ?rex:regexp ->
-+  ?pat:string ->
-+  ?pos:int ->
-+  ?max:int ->
-+  ?callout:callout ->
-+  string ->
-+  split_result list
-+(** [full_split ?iflags ?flags ?rex ?pat ?pos ?max ?callout subj] splits [subj]
-+    into a list of at most [max] elements of type "split_result", using as
-+    delimiter pattern [pat] when given, regular expression [rex] otherwise,
-+    starting at position [pos]. Uses [flags] when given, the precompiled
-+    [iflags] otherwise. If [max] is zero, trailing empty fields are stripped. If
-+    it is negative, it is treated as arbitrarily large. Should behave exactly as
-+    in PERL. Callouts are handled by [callout].
-+
-+    @param iflags default = no extra flags
-+    @param flags default = ignored
-+    @param rex default = matches whitespace
-+    @param pat default = ignored
-+    @param pos default = 0
-+    @param max default = 0
-+    @param callout default = ignore callouts *)
-+
-+(** {1 Additional convenience functions} *)
-+
-+val foreach_line : ?ic:in_channel -> (string -> unit) -> unit
-+(** [foreach_line ?ic f] applies [f] to each line in inchannel [ic] until the
-+    end-of-file is reached.
-+
-+    @param ic default = stdin *)
-+
-+val foreach_file : string list -> (string -> in_channel -> unit) -> unit
-+(** [foreach_file filenames f] opens each file in the list [filenames] for input
-+    and applies [f] to each filename and the corresponding channel. Channels are
-+    closed after each operation (even when exceptions occur - they get reraised
-+    afterwards!). *)
-+
-+(** {1 {b UNSAFE STUFF - USE WITH CAUTION!}} *)
-+
-+val unsafe_pcre2_match :
-+  irflag ->
-+  regexp ->
-+  pos:int ->
-+  subj_start:int ->
-+  subj:string ->
-+  int array ->
-+  callout option ->
-+  unit
-+(** [unsafe_pcre_exec flags rex ~pos ~subj_start ~subj offset_vector callout].
-+    You should read the C-source to know what happens. If you do not understand
-+    it - {b don't use this function!} *)
-+
-+val make_ovector : regexp -> int * int array
-+(** [make_ovector regexp] calculates the tuple (subgroups2, ovector) which is
-+    the number of subgroup offsets and the offset array. *)
-+
-+val unsafe_pcre2_dfa_match :
-+  irflag ->
-+  regexp ->
-+  pos:int ->
-+  subj_start:int ->
-+  subj:string ->
-+  int array ->
-+  callout option ->
-+  workspace:int array ->
-+  unit
-+(** [unsafe_pcre_dfa_exec flags rex ~pos ~subj_start ~subj offset_vector callout
-+     ~workpace]. You should read the C-source to know what happens. If you do
-+    not understand it - {b don't use this function!} *)
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c b/bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c
-new file mode 100644
-index 000000000..c923ae29a
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c
-@@ -0,0 +1,807 @@
-+/*
-+   PCRE2-OCAML - Perl Compatibility Regular Expressions for OCaml
-+
-+   Copyright © 1999- Markus Mottl <markus.mottl@gmail.com>
-+
-+   This library is free software; you can redistribute it and/or
-+   modify it under the terms of the GNU Lesser General Public
-+   License as published by the Free Software Foundation; either
-+   version 2.1 of the License, or (at your option) any later version.
-+
-+   This library 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
-+   Lesser General Public License for more details.
-+
-+   You should have received a copy of the GNU Lesser General Public
-+   License along with this library; if not, write to the Free Software
-+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
-+*/
-+
-+#if defined(_WIN32)
-+#define snprintf _snprintf
-+#if defined(_DLL)
-+#define PCREextern __declspec(dllexport)
-+#else
-+#define PCREextern
-+#endif
-+#endif
-+
-+#if defined(_WIN64)
-+typedef long long *caml_int_ptr;
-+#else
-+typedef long *caml_int_ptr;
-+#endif
-+
-+#if __GNUC__ >= 3
-+#define __unused __attribute__((unused))
-+#else
-+#define __unused
-+#endif
-+
-+#include <ctype.h>
-+#include <stdio.h>
-+#include <string.h>
-+
-+#include <caml/alloc.h>
-+#include <caml/callback.h>
-+#include <caml/custom.h>
-+#include <caml/fail.h>
-+#include <caml/memory.h>
-+#include <caml/mlvalues.h>
-+#include <caml/version.h>
-+
-+#if (OCAML_VERSION_MAJOR == 4) && (OCAML_VERSION_MINOR < 12)
-+#define Val_none (Val_long(0))
-+#define Some_val(v) Field(v, 0)
-+#define Tag_some 0
-+#define Is_none(v) ((v) == Val_none)
-+#define Is_some(v) Is_block(v)
-+
-+CAMLexport static value caml_alloc_some(value v) {
-+  CAMLparam1(v);
-+  value some = caml_alloc_small(1, 0);
-+  Field(some, 0) = v;
-+  CAMLreturn(some);
-+}
-+#endif
-+
-+#define PCRE2_CODE_UNIT_WIDTH 8
-+
-+#include <pcre2.h>
-+
-+typedef const unsigned char *chartables; /* Type of chartable sets */
-+
-+/* Contents of callout data */
-+struct cod {
-+  long subj_start;       /* Start of subject string */
-+  value *v_substrings_p; /* Pointer to substrings matched so far */
-+  value *v_cof_p;        /* Pointer to callout function */
-+  value v_exn;           /* Possible exception raised by callout function */
-+};
-+
-+/* Cache for exceptions */
-+static const value *pcre2_exc_Error = NULL;     /* Exception [Error] */
-+static const value *pcre2_exc_Backtrack = NULL; /* Exception [Backtrack] */
-+
-+/* Cache for polymorphic variants */
-+static value var_Start_only; /* Variant [`Start_only] */
-+static value var_ANCHORED;   /* Variant [`ANCHORED] */
-+static value var_Char;       /* Variant [`Char char] */
-+
-+/* Data associated with OCaml values of PCRE regular expression */
-+struct pcre2_ocaml_regexp {
-+  pcre2_code *rex;
-+  pcre2_match_context *mcontext;
-+};
-+
-+#define Pcre2_ocaml_regexp_val(v)                                              \
-+  ((struct pcre2_ocaml_regexp *)Data_custom_val(v))
-+
-+#define get_rex(v) Pcre2_ocaml_regexp_val(v)->rex
-+#define get_mcontext(v) Pcre2_ocaml_regexp_val(v)->mcontext
-+
-+#define set_rex(v, r) Pcre2_ocaml_regexp_val(v)->rex = r
-+#define set_mcontext(v, c) Pcre2_ocaml_regexp_val(v)->mcontext = c
-+
-+/* Data associated with OCaml values of PCRE tables */
-+struct pcre2_ocaml_tables {
-+  chartables tables;
-+};
-+
-+#define Pcre2_ocaml_tables_val(v)                                              \
-+  ((struct pcre2_ocaml_tables *)Data_custom_val(v))
-+
-+#define get_tables(v) Pcre2_ocaml_tables_val(v)->tables
-+#define set_tables(v, t) Pcre2_ocaml_tables_val(v)->tables = t
-+
-+/* Converts subject offsets from C-integers to OCaml-Integers.
-+
-+   This is a bit tricky, because there are 32- and 64-bit platforms around
-+   and OCaml chooses the larger possibility for representing integers when
-+   available (also in arrays) - not so the PCRE!
-+*/
-+static inline void copy_ovector(long subj_start, const size_t *ovec_src,
-+                                caml_int_ptr ovec_dst, uint32_t subgroups2) {
-+  if (subj_start == 0)
-+    while (subgroups2--) {
-+      *ovec_dst = (*ovec_src == PCRE2_UNSET) ? Val_int(-1) : Val_int(*ovec_src);
-+      --ovec_src;
-+      --ovec_dst;
-+    }
-+  else
-+    while (subgroups2--) {
-+      *ovec_dst = (*ovec_src == PCRE2_UNSET) ? Val_int(-1)
-+                                             : Val_long(*ovec_src + subj_start);
-+      --ovec_src;
-+      --ovec_dst;
-+    }
-+}
-+
-+/* Callout handler */
-+static int pcre2_callout_handler(pcre2_callout_block *cb, struct cod *cod) {
-+  if (cod != NULL) {
-+    /* Callout is available */
-+    value v_res;
-+
-+    /* Set up parameter array */
-+    value v_callout_data = caml_alloc_small(8, 0);
-+
-+    const value v_substrings = *cod->v_substrings_p;
-+
-+    const uint32_t capture_top = cb->capture_top;
-+    uint32_t subgroups2 = capture_top << 1;
-+    const uint32_t subgroups2_1 = subgroups2 - 1;
-+
-+    const size_t *ovec_src = cb->offset_vector + subgroups2_1;
-+    caml_int_ptr ovec_dst =
-+        (caml_int_ptr)&Field(Field(v_substrings, 1), 0) + subgroups2_1;
-+    long subj_start = cod->subj_start;
-+
-+    copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
-+
-+    Field(v_callout_data, 0) = Val_int(cb->callout_number);
-+    Field(v_callout_data, 1) = v_substrings;
-+    Field(v_callout_data, 2) = Val_int(cb->start_match + subj_start);
-+    Field(v_callout_data, 3) = Val_int(cb->current_position + subj_start);
-+    Field(v_callout_data, 4) = Val_int(capture_top);
-+    Field(v_callout_data, 5) = Val_int(cb->capture_last);
-+    Field(v_callout_data, 6) = Val_int(cb->pattern_position);
-+    Field(v_callout_data, 7) = Val_int(cb->next_item_length);
-+
-+    /* Perform callout */
-+    v_res = caml_callback_exn(*cod->v_cof_p, v_callout_data);
-+
-+    if (Is_exception_result(v_res)) {
-+      /* Callout raised an exception */
-+      const value v_exn = Extract_exception(v_res);
-+      if (Field(v_exn, 0) == *pcre2_exc_Backtrack)
-+        return 1;
-+      cod->v_exn = v_exn;
-+      return PCRE2_ERROR_CALLOUT;
-+    }
-+  }
-+
-+  return 0;
-+}
-+
-+/* Fetches the named OCaml-values + caches them and
-+   calculates + caches the variant hash values */
-+CAMLprim value pcre2_ocaml_init(value __unused v_unit) {
-+  pcre2_exc_Error = caml_named_value("Pcre2.Error");
-+  pcre2_exc_Backtrack = caml_named_value("Pcre2.Backtrack");
-+
-+  var_Start_only = caml_hash_variant("Start_only");
-+  var_ANCHORED = caml_hash_variant("ANCHORED");
-+  var_Char = caml_hash_variant("Char");
-+
-+  return Val_unit;
-+}
-+
-+/* Finalizing deallocation function for chartable sets */
-+static void pcre2_dealloc_tables(value v_tables) {
-+#if PCRE2_MINOR >= 34
-+  pcre2_maketables_free(NULL, get_tables(v_tables));
-+#else
-+  free((void *)get_tables(v_tables));
-+#endif
-+}
-+
-+/* Finalizing deallocation function for compiled regular expressions */
-+static void pcre2_dealloc_regexp(value v_rex) {
-+  pcre2_code_free(get_rex(v_rex));
-+  pcre2_match_context_free(get_mcontext(v_rex));
-+}
-+
-+/* Raising exceptions */
-+
-+CAMLnoreturn_start static inline void
-+raise_pcre2_error(value v_arg) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void raise_partial(void) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void raise_bad_utf(void) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void
-+raise_bad_utf_offset(void) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void raise_match_limit(void) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void raise_depth_limit(void) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void
-+raise_workspace_size(void) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void
-+raise_bad_pattern(int code, size_t pos) CAMLnoreturn_end;
-+
-+CAMLnoreturn_start static inline void
-+raise_internal_error(char *msg) CAMLnoreturn_end;
-+
-+static inline void raise_pcre2_error(value v_arg) {
-+  caml_raise_with_arg(*pcre2_exc_Error, v_arg);
-+}
-+
-+static inline void raise_partial(void) { raise_pcre2_error(Val_int(0)); }
-+static inline void raise_bad_utf(void) { raise_pcre2_error(Val_int(1)); }
-+static inline void raise_bad_utf_offset(void) { raise_pcre2_error(Val_int(2)); }
-+static inline void raise_match_limit(void) { raise_pcre2_error(Val_int(3)); }
-+static inline void raise_depth_limit(void) { raise_pcre2_error(Val_int(4)); }
-+static inline void raise_workspace_size(void) { raise_pcre2_error(Val_int(5)); }
-+
-+/* The length of msg_buf in this function is chosen to be larger than
-+   any existing error-message in pcre2_error.c.  Currently (Feb 25, 2025, Git
-+   commit 0880a6c33a51e2dfded8864a6bcc8ae4e9a90f89),  the longest error-message
-+   is about 110 chars.  Uncomfortably close to 128, so I doubled the length to
-+   256.
-+*/
-+
-+static inline void raise_bad_pattern(int code, size_t pos) {
-+  CAMLparam0();
-+  CAMLlocal2(v_msg, v_arg);
-+  char msg_buf[128];
-+  pcre2_get_error_message(code, (PCRE2_UCHAR *)msg_buf,
-+                          (sizeof msg_buf) / (sizeof(PCRE2_UCHAR)));
-+  v_msg = caml_copy_string(msg_buf);
-+  v_arg = caml_alloc_small(2, 0);
-+  Field(v_arg, 0) = v_msg;
-+  Field(v_arg, 1) = Val_int(pos);
-+  raise_pcre2_error(v_arg);
-+  CAMLnoreturn;
-+}
-+
-+static inline void raise_internal_error(char *msg) {
-+  CAMLparam0();
-+  CAMLlocal1(v_msg);
-+  value v_arg;
-+  v_msg = caml_copy_string(msg);
-+  v_arg = caml_alloc_small(1, 1);
-+  Field(v_arg, 0) = v_msg;
-+  raise_pcre2_error(v_arg);
-+  CAMLnoreturn;
-+}
-+
-+/* PCRE pattern compilation */
-+
-+static struct custom_operations regexp_ops = {
-+    "pcre2_ocaml_regexp",       pcre2_dealloc_regexp,
-+    custom_compare_default,     custom_hash_default,
-+    custom_serialize_default,   custom_deserialize_default,
-+    custom_compare_ext_default, custom_fixed_length_default};
-+
-+/* Makes compiled regular expression from compilation options, an optional
-+   value of chartables and the pattern string */
-+
-+CAMLprim value pcre2_compile_stub(int64_t v_opt, value v_tables, value v_pat) {
-+  value v_rex; /* Final result -> value of type [regexp] */
-+  size_t regexp_size, ocaml_regexp_size = sizeof(struct pcre2_ocaml_regexp);
-+  int error_code = 0;   /* error code for potential error */
-+  size_t error_ofs = 0; /* offset in the pattern at which error occurred */
-+  size_t length = caml_string_length(v_pat);
-+
-+  pcre2_compile_context *ccontext = NULL;
-+  /* If v_tables = [None], then pointer to tables is NULL, otherwise
-+     set it to the appropriate value */
-+  if (Is_some(v_tables)) {
-+    ccontext = pcre2_compile_context_create(NULL);
-+    pcre2_set_character_tables(ccontext, get_tables(Field(v_tables, 0)));
-+  }
-+
-+  /* Compiles the pattern */
-+  pcre2_code *regexp = pcre2_compile((PCRE2_SPTR)String_val(v_pat), length,
-+                                     v_opt, &error_code, &error_ofs, ccontext);
-+
-+  pcre2_compile_context_free(ccontext);
-+
-+  /* Raises appropriate exception with [BadPattern] if the pattern
-+     could not be compiled */
-+  if (regexp == NULL)
-+    raise_bad_pattern(error_code, error_ofs);
-+
-+  /* It's unknown at this point whether JIT compilation is going to be used,
-+     but we have to decide on a size.  Tests with some simple patterns indicate
-+     a roughly 50% increase in size when studying without JIT.  A factor of two
-+     times hence seems like a reasonable bound to use here. */
-+  pcre2_pattern_info(regexp, PCRE2_INFO_SIZE, &regexp_size);
-+  v_rex =
-+      caml_alloc_custom_mem(&regexp_ops, ocaml_regexp_size, 2 * regexp_size);
-+
-+  set_rex(v_rex, regexp);
-+  set_mcontext(v_rex, pcre2_match_context_create(NULL));
-+
-+  return v_rex;
-+}
-+
-+CAMLprim value pcre2_compile_stub_bc(value v_opt, value v_tables, value v_pat) {
-+  return pcre2_compile_stub(Int64_val(v_opt), v_tables, v_pat);
-+}
-+
-+/* Gets the depth limit of a regular expression if it exists */
-+/* CAMLprim value pcre2_get_depth_limit_stub(value v_rex); */
-+
-+/* Gets the match limit of a regular expression if it exists */
-+/* CAMLprim value pcre2_get_match_limit_stub(value v_rex); */
-+
-+/* Sets a match limit for a regular expression imperatively */
-+
-+CAMLprim value pcre2_set_imp_match_limit_stub(value v_rex, intnat v_lim) {
-+  pcre2_match_context *mcontext = get_mcontext(v_rex);
-+  pcre2_set_match_limit(mcontext, v_lim);
-+  return v_rex;
-+}
-+
-+CAMLprim value pcre2_set_imp_match_limit_stub_bc(value v_rex, value v_lim) {
-+  return pcre2_set_imp_match_limit_stub(v_rex, Int_val(v_lim));
-+}
-+
-+/* Sets a depth limit for a regular expression imperatively */
-+
-+CAMLprim value pcre2_set_imp_depth_limit_stub(value v_rex, intnat v_lim) {
-+  pcre2_match_context *mcontext = get_mcontext(v_rex);
-+  pcre2_set_depth_limit(mcontext, v_lim);
-+  return v_rex;
-+}
-+
-+CAMLprim value pcre2_set_imp_depth_limit_stub_bc(value v_rex, value v_lim) {
-+  return pcre2_set_imp_depth_limit_stub(v_rex, Int_val(v_lim));
-+}
-+
-+/* Performs the call to the pcre2_pattern_info function */
-+static inline int pcre2_pattern_info_stub(value v_rex, int what, void *where) {
-+  return pcre2_pattern_info(get_rex(v_rex), what, where);
-+}
-+
-+/* Some stubs for info-functions */
-+
-+/* Generic macro for getting integer results from pcre2_pattern_info */
-+#define MAKE_INTNAT_INFO(tp, name, option)                                     \
-+  CAMLprim intnat pcre2_##name##_stub(value v_rex) {                           \
-+    tp options;                                                                \
-+    const int ret =                                                            \
-+        pcre2_pattern_info_stub(v_rex, PCRE2_INFO_##option, &options);         \
-+    if (ret != 0)                                                              \
-+      raise_internal_error("pcre2_##name##_stub");                             \
-+    return options;                                                            \
-+  }                                                                            \
-+                                                                               \
-+  CAMLprim value pcre2_##name##_stub_bc(value v_rex) {                         \
-+    return Val_int(pcre2_##name##_stub(v_rex));                                \
-+  }
-+
-+MAKE_INTNAT_INFO(size_t, size, SIZE)
-+MAKE_INTNAT_INFO(int, capturecount, CAPTURECOUNT)
-+MAKE_INTNAT_INFO(int, backrefmax, BACKREFMAX)
-+MAKE_INTNAT_INFO(int, namecount, NAMECOUNT)
-+MAKE_INTNAT_INFO(int, nameentrysize, NAMEENTRYSIZE)
-+
-+CAMLprim int64_t pcre2_argoptions_stub(value v_rex) {
-+  uint32_t options;
-+  const int ret =
-+      pcre2_pattern_info_stub(v_rex, PCRE2_INFO_ARGOPTIONS, &options);
-+  if (ret != 0)
-+    raise_internal_error("pcre2_argoptions_stub");
-+  return (int64_t)options;
-+}
-+
-+CAMLprim value pcre2_argoptions_stub_bc(value v_rex) {
-+  CAMLparam1(v_rex);
-+  CAMLreturn(caml_copy_int64(pcre2_argoptions_stub(v_rex)));
-+}
-+
-+CAMLprim value pcre2_firstcodeunit_stub(value v_rex) {
-+  uint32_t firstcodetype;
-+  const int ret =
-+      pcre2_pattern_info_stub(v_rex, PCRE2_INFO_FIRSTCODETYPE, &firstcodetype);
-+
-+  if (ret != 0)
-+    raise_internal_error("pcre2_firstcodeunit_stub");
-+
-+  switch (firstcodetype) {
-+  case 2:
-+    return var_Start_only;
-+    break; /* [`Start_only] */
-+  case 0:
-+    return var_ANCHORED;
-+    break; /* [`ANCHORED] */
-+  case 1: {
-+    uint32_t firstcodeunit;
-+    const int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_FIRSTCODEUNIT,
-+                                            &firstcodeunit);
-+    if (ret != 0)
-+      raise_internal_error("pcre2_firstcodeunit_stub");
-+
-+    value v_firstbyte;
-+    /* Allocates the non-constant constructor [`Char of char] and fills
-+       in the appropriate value */
-+    v_firstbyte = caml_alloc_small(2, 0);
-+    Field(v_firstbyte, 0) = var_Char;
-+    Field(v_firstbyte, 1) = Val_int(firstcodeunit);
-+
-+    return v_firstbyte;
-+    break;
-+  }
-+  default: /* Should not happen */
-+    raise_internal_error("pcre2_firstcodeunit_stub");
-+  }
-+}
-+
-+CAMLprim value pcre2_lastcodeunit_stub(value v_rex) {
-+  uint32_t lastcodetype;
-+  const int ret =
-+      pcre2_pattern_info_stub(v_rex, PCRE2_INFO_LASTCODETYPE, &lastcodetype);
-+
-+  if (ret != 0)
-+    raise_internal_error("pcre2_lastcodeunit_stub");
-+
-+  if (lastcodetype == 0)
-+    return Val_none;
-+  if (lastcodetype != 1)
-+    raise_internal_error("pcre2_lastcodeunit_stub");
-+  else {
-+    uint32_t lastcodeunit;
-+    const int ret =
-+        pcre2_pattern_info_stub(v_rex, PCRE2_INFO_LASTCODEUNIT, &lastcodeunit);
-+    if (ret != 0)
-+      raise_internal_error("pcre2_lastcodeunit_stub");
-+    return caml_alloc_some(Val_int(lastcodeunit));
-+  }
-+}
-+
-+CAMLnoreturn_start static inline void
-+handle_match_error(char *loc, const int ret) CAMLnoreturn_end;
-+
-+static inline void handle_match_error(char *loc, const int ret) {
-+  switch (ret) {
-+  /* Dedicated exceptions */
-+  case PCRE2_ERROR_NOMATCH:
-+    caml_raise_not_found();
-+  case PCRE2_ERROR_PARTIAL:
-+    raise_partial();
-+  case PCRE2_ERROR_MATCHLIMIT:
-+    raise_match_limit();
-+  case PCRE2_ERROR_BADUTFOFFSET:
-+    raise_bad_utf_offset();
-+  case PCRE2_ERROR_DEPTHLIMIT:
-+    raise_depth_limit();
-+  case PCRE2_ERROR_DFA_WSSIZE:
-+    raise_workspace_size();
-+  default: {
-+    if (PCRE2_ERROR_UTF8_ERR21 <= ret && ret <= PCRE2_ERROR_UTF8_ERR1)
-+      raise_bad_utf();
-+    /* Unknown error */
-+    char err_buf[100];
-+    snprintf(err_buf, 100, "%s: unhandled PCRE2 error code: %d", loc, ret);
-+    raise_internal_error(err_buf);
-+  }
-+  }
-+}
-+
-+static inline void handle_pcre2_match_result(size_t *ovec, value v_ovec,
-+                                             size_t ovec_len, long subj_start,
-+                                             uint32_t ret) {
-+  caml_int_ptr ocaml_ovec = (caml_int_ptr)&Field(v_ovec, 0);
-+  const uint32_t subgroups2 = ret * 2;
-+  const uint32_t subgroups2_1 = subgroups2 - 1;
-+  const size_t *ovec_src = ovec + subgroups2_1;
-+  caml_int_ptr ovec_clear_stop = ocaml_ovec + (ovec_len * 2) / 3;
-+  caml_int_ptr ovec_dst = ocaml_ovec + subgroups2_1;
-+  copy_ovector(subj_start, ovec_src, ovec_dst, subgroups2);
-+  while (++ovec_dst < ovec_clear_stop)
-+    *ovec_dst = -1;
-+}
-+
-+/* Executes a pattern match with runtime options, a regular expression, a
-+   matching position, the start of the subject string, a subject string,
-+   a number of subgroup offsets, an offset vector and an optional callout
-+   function */
-+
-+CAMLprim value pcre2_match_stub0(int64_t v_opt, value v_rex, intnat v_pos,
-+                                 intnat v_subj_start, value v_subj,
-+                                 value v_ovec, value v_maybe_cof,
-+                                 value v_workspace) {
-+  int ret;
-+  int is_dfa = v_workspace != (value)NULL;
-+  long pos = v_pos, subj_start = v_subj_start;
-+  size_t ovec_len = Wosize_val(v_ovec), len = caml_string_length(v_subj);
-+
-+  if (pos > (long)len || pos < subj_start)
-+    caml_invalid_argument("Pcre2.pcre2_match_stub: illegal position");
-+
-+  if (subj_start > (long)len || subj_start < 0)
-+    caml_invalid_argument("Pcre2.pcre2_match_stub: illegal subject start");
-+
-+  pos -= subj_start;
-+  len -= subj_start;
-+
-+  {
-+    const pcre2_code *code = get_rex(v_rex);             /* Compiled pattern */
-+    pcre2_match_context *mcontext = get_mcontext(v_rex); /* Match context */
-+    PCRE2_SPTR ocaml_subj =
-+        (PCRE2_SPTR)String_val(v_subj) + subj_start; /* Subject string */
-+
-+    pcre2_match_data *match_data =
-+        pcre2_match_data_create_from_pattern(code, NULL);
-+
-+    /* Special case when no callout functions specified */
-+    if (Is_none(v_maybe_cof)) {
-+      /* Performs the match */
-+      if (is_dfa)
-+        ret = pcre2_dfa_match(code, ocaml_subj, len, pos, v_opt, match_data,
-+                              mcontext, (int *)&Field(v_workspace, 0),
-+                              Wosize_val(v_workspace));
-+      else
-+        ret = pcre2_match(code, ocaml_subj, len, pos, v_opt, match_data,
-+                          mcontext);
-+
-+      size_t *ovec = pcre2_get_ovector_pointer(match_data);
-+
-+      if (ret < 0) {
-+        pcre2_match_data_free(match_data);
-+        handle_match_error("pcre2_match_stub", ret);
-+      } else {
-+        handle_pcre2_match_result(ovec, v_ovec, ovec_len, subj_start, ret);
-+      }
-+    }
-+
-+    /* There are callout functions */
-+    else {
-+      value v_cof = Field(v_maybe_cof, 0);
-+      value v_substrings;
-+      PCRE2_UCHAR *subj = caml_stat_alloc(sizeof(char) * len);
-+      int workspace_len = 0;
-+      int *workspace = NULL;
-+      struct cod cod = {0, (value *)NULL, (value *)NULL, (value)NULL};
-+      pcre2_match_context *new_mcontext = pcre2_match_context_copy(mcontext);
-+
-+      pcre2_set_callout(
-+          new_mcontext,
-+          (int (*)(pcre2_callout_block_8 *, void *))&pcre2_callout_handler,
-+          &cod);
-+
-+      cod.subj_start = subj_start;
-+      memcpy(subj, ocaml_subj, len);
-+
-+      Begin_roots4(v_rex, v_cof, v_substrings, v_ovec);
-+      Begin_roots1(v_subj);
-+      v_substrings = caml_alloc_small(2, 0);
-+      End_roots();
-+
-+      Field(v_substrings, 0) = v_subj;
-+      Field(v_substrings, 1) = v_ovec;
-+
-+      cod.v_substrings_p = &v_substrings;
-+      cod.v_cof_p = &v_cof;
-+
-+      if (is_dfa) {
-+        workspace_len = Wosize_val(v_workspace);
-+        workspace = caml_stat_alloc(sizeof(int) * workspace_len);
-+        ret = pcre2_dfa_match(code, subj, len, pos, v_opt, match_data,
-+                              new_mcontext, (int *)&Field(v_workspace, 0),
-+                              workspace_len);
-+      } else
-+        ret =
-+            pcre2_match(code, subj, len, pos, v_opt, match_data, new_mcontext);
-+
-+      caml_stat_free(subj);
-+      End_roots();
-+
-+      pcre2_match_context_free(new_mcontext);
-+      size_t *ovec = pcre2_get_ovector_pointer(match_data);
-+      if (ret < 0) {
-+        if (is_dfa)
-+          caml_stat_free(workspace);
-+        pcre2_match_data_free(match_data);
-+        if (ret == PCRE2_ERROR_CALLOUT)
-+          caml_raise(cod.v_exn);
-+        else
-+          handle_match_error("pcre2_match_stub(callout)", ret);
-+      } else {
-+        handle_pcre2_match_result(ovec, v_ovec, ovec_len, subj_start, ret);
-+        if (is_dfa) {
-+          caml_int_ptr ocaml_workspace_dst =
-+              (caml_int_ptr)&Field(v_workspace, 0);
-+          const int *workspace_src = workspace;
-+          const int *workspace_src_stop = workspace + workspace_len;
-+          while (workspace_src != workspace_src_stop) {
-+            *ocaml_workspace_dst = *workspace_src;
-+            ocaml_workspace_dst++;
-+            workspace_src++;
-+          }
-+          caml_stat_free(workspace);
-+        }
-+      }
-+    }
-+    pcre2_match_data_free(match_data);
-+  }
-+
-+  return Val_unit;
-+}
-+
-+CAMLprim value pcre2_match_stub(int64_t v_opt, value v_rex, intnat v_pos,
-+                                intnat v_subj_start, value v_subj, value v_ovec,
-+                                value v_maybe_cof) {
-+  return pcre2_match_stub0(v_opt, v_rex, v_pos, v_subj_start, v_subj, v_ovec,
-+                           v_maybe_cof, (value)NULL);
-+}
-+
-+/* Byte-code hook for pcre2_match_stub
-+   Needed, because there are more than 5 arguments */
-+CAMLprim value pcre2_match_stub_bc(value *argv, int __unused argn) {
-+  return pcre2_match_stub0(Int64_val(argv[0]), argv[1], Int_val(argv[2]),
-+                           Int_val(argv[3]), argv[4], argv[5], argv[6],
-+                           (value)NULL);
-+}
-+
-+/* Byte-code hook for pcre2_dfa_match_stub
-+   Needed, because there are more than 5 arguments */
-+CAMLprim value pcre2_dfa_match_stub_bc(value *argv, int __unused argn) {
-+  return pcre2_match_stub0(Int64_val(argv[0]), argv[1], Int_val(argv[2]),
-+                           Int_val(argv[3]), argv[4], argv[5], argv[6],
-+                           argv[7]);
-+}
-+
-+static struct custom_operations tables_ops = {
-+    "pcre2_ocaml_tables",       pcre2_dealloc_tables,
-+    custom_compare_default,     custom_hash_default,
-+    custom_serialize_default,   custom_deserialize_default,
-+    custom_compare_ext_default, custom_fixed_length_default};
-+
-+/* Generates a new set of chartables for the current locale (see man
-+   page of PCRE */
-+CAMLprim value pcre2_maketables_stub(value __unused v_unit) {
-+  /* According to testing with `malloc_size`, it seems that a typical set of
-+     tables will require about 1536 bytes of memory.  This may or may not
-+     be true on other platforms or for all versions of PCRE.  Since there
-+     is apparently no reliable way of finding out, 1536 is probably a good
-+     default value. */
-+  size_t tables_size = sizeof(struct pcre2_ocaml_tables);
-+  const value v_tables = caml_alloc_custom_mem(&tables_ops, tables_size, 1536);
-+  set_tables(v_tables, pcre2_maketables(NULL));
-+  return v_tables;
-+}
-+
-+/* Wraps around the isspace-function */
-+CAMLprim value pcre2_isspace_stub(value v_c) {
-+  return Val_bool(isspace(Int_val(v_c)));
-+}
-+
-+/* Returns number of substring associated with a name */
-+
-+CAMLprim intnat pcre2_substring_number_from_name_stub(value v_rex,
-+                                                      value v_name) {
-+  const int ret = pcre2_substring_number_from_name(
-+      get_rex(v_rex), (PCRE2_SPTR)String_val(v_name));
-+  if (ret == PCRE2_ERROR_NOSUBSTRING)
-+    caml_invalid_argument("Named string not found");
-+
-+  return ret;
-+}
-+
-+CAMLprim value pcre2_substring_number_from_name_stub_bc(value v_rex,
-+                                                        value v_name) {
-+  return Val_int(pcre2_substring_number_from_name_stub(v_rex, v_name));
-+}
-+
-+/* Returns array of names of named substrings in a regexp */
-+CAMLprim value pcre2_names_stub(value v_rex) {
-+  CAMLparam1(v_rex);
-+  CAMLlocal1(v_res);
-+  uint32_t name_count;
-+  uint32_t entry_size;
-+  const char *tbl_ptr;
-+  uint32_t i;
-+
-+  int ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_NAMECOUNT, &name_count);
-+  if (ret != 0)
-+    raise_internal_error("pcre2_names_stub: namecount");
-+
-+  ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_NAMEENTRYSIZE, &entry_size);
-+  if (ret != 0)
-+    raise_internal_error("pcre2_names_stub: nameentrysize");
-+
-+  ret = pcre2_pattern_info_stub(v_rex, PCRE2_INFO_NAMETABLE, &tbl_ptr);
-+  if (ret != 0)
-+    raise_internal_error("pcre2_names_stub: nametable");
-+
-+  v_res = caml_alloc(name_count, 0);
-+
-+  for (i = 0; i < name_count; ++i) {
-+    value v_name = caml_copy_string(tbl_ptr + 2);
-+    Store_field(v_res, i, v_name);
-+    tbl_ptr += entry_size;
-+  }
-+
-+  CAMLreturn(v_res);
-+}
-+
-+/* Generic stub for getting integer results from pcre2_config */
-+static inline int pcre2_config_int(int what) {
-+  int ret;
-+  pcre2_config(what, (void *)&ret);
-+  return ret;
-+}
-+
-+/* Generic stub for getting long integer results from pcre2_config */
-+static inline long pcre2_config_long(int what) {
-+  long ret;
-+  pcre2_config(what, (void *)&ret);
-+  return ret;
-+}
-+
-+/* Some stubs for config-functions */
-+
-+/* Makes OCaml-string from PCRE-version */
-+CAMLprim value pcre2_version_stub(value __unused v_unit) {
-+  CAMLparam1(v_unit);
-+  CAMLlocal1(v_version);
-+  v_version = caml_alloc_string(32);
-+
-+  pcre2_config(PCRE2_CONFIG_VERSION, (void *)String_val(v_version));
-+
-+  CAMLreturn(v_version);
-+}
-+
-+/* Returns boolean indicating unicode support */
-+CAMLprim value pcre2_config_unicode_stub(value __unused v_unit) {
-+  return Val_bool(pcre2_config_int(PCRE2_CONFIG_UNICODE));
-+}
-+
-+/* Returns character used as newline */
-+CAMLprim value pcre2_config_newline_stub(value __unused v_unit) {
-+  return Val_int(pcre2_config_int(PCRE2_CONFIG_NEWLINE));
-+}
-+
-+/* Returns number of bytes used for internal linkage of regular expressions */
-+
-+CAMLprim intnat pcre2_config_link_size_stub(value __unused v_unit) {
-+  return pcre2_config_int(PCRE2_CONFIG_LINKSIZE);
-+}
-+
-+CAMLprim value pcre2_config_link_size_stub_bc(value v_unit) {
-+  return Val_int(pcre2_config_link_size_stub(v_unit));
-+}
-+
-+/* Returns default limit for calls to internal matching function */
-+
-+CAMLprim intnat pcre2_config_match_limit_stub(value __unused v_unit) {
-+  return pcre2_config_long(PCRE2_CONFIG_MATCHLIMIT);
-+}
-+
-+CAMLprim value pcre2_config_match_limit_stub_bc(value v_unit) {
-+  return Val_int(pcre2_config_match_limit_stub(v_unit));
-+}
-+
-+/* Returns default limit for depth of nested backtracking  */
-+
-+CAMLprim intnat pcre2_config_depth_limit_stub(value __unused v_unit) {
-+  return pcre2_config_long(PCRE2_CONFIG_DEPTHLIMIT);
-+}
-+
-+CAMLprim value pcre2_config_depth_limit_stub_bc(value v_unit) {
-+  return Val_int(pcre2_config_depth_limit_stub(v_unit));
-+}
-+
-+/* Returns boolean indicating use of stack recursion */
-+CAMLprim intnat pcre2_config_stackrecurse_stub(value __unused v_unit) {
-+  return Val_bool(pcre2_config_int(PCRE2_CONFIG_STACKRECURSE));
-+}
-diff --git a/bundles/pcre2/pcre2-ocaml/pa_ppx_test/Makefile b/bundles/pcre2/pcre2-ocaml/pa_ppx_test/Makefile
-new file mode 100644
-index 000000000..e35bbc1f1
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/pa_ppx_test/Makefile
-@@ -0,0 +1,11 @@
-+NOT_OCAMLFIND=not-ocamlfind
-+
-+bootstrap: ../test/pcre2_tests.ml
-+
-+../test/%.ml: %.ml
-+	$(NOT_OCAMLFIND) preprocess \
-+		-package pa_ppx_regexp,camlp5.pr_o -ppopt -pa_ppx_regexp-nostatic \
-+		-syntax camlp5o $< > $@.NEW && \
-+	mv $@.NEW $@
-+
-+.SUFFIXES: .ml
-diff --git a/bundles/pcre2/pcre2-ocaml/pa_ppx_test/pcre2_tests.ml b/bundles/pcre2/pcre2-ocaml/pa_ppx_test/pcre2_tests.ml
-new file mode 100644
-index 000000000..79c9ac763
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/pa_ppx_test/pcre2_tests.ml
-@@ -0,0 +1,249 @@
-+open OUnit2
-+(**pp -syntax camlp5o -package pa_ppx.deriving_plugins.std *)
-+
-+let test_special_char_regexps ctxt =
-+  ();
-+  assert_equal "\n" ([%match {|\n$|} / s exc pcre2 strings] "\n");
-+  assert_equal "" ([%subst {|\n+$|} / {||} / s pcre2] "\n\n")
-+
-+let test_pcre2_simple_match ctxt =
-+  ();
-+  assert_equal "abc"
-+    (Pcre2.get_substring ([%match "abc" / exc raw pcre2] "abc") 0);
-+  assert_equal (Some "abc") ([%match "abc" / pcre2] "abc");
-+  assert_equal (Some "abc") ([%match "abc" / strings pcre2] "abc");
-+  assert_equal true ([%match "abc" / pred pcre2] "abc");
-+  assert_equal false ([%match "abc" / pred pcre2] "abd");
-+  assert_equal None ([%match "abc" / pcre2] "abd");
-+  assert_raises Not_found (fun () -> [%match "abc" / exc pcre2] "abd");
-+  assert_raises Not_found (fun () -> [%match "abc" / exc strings pcre2] "abd");
-+  assert_equal None ([%match "abc" / strings pcre2] "abd");
-+  assert_equal "abc" ([%match "abc" / exc strings pcre2] "abc");
-+  assert_equal ("abc", Some "b") ([%match "a(b)c" / exc strings pcre2] "abc");
-+  assert_equal ("ac", None) ([%match "a(?:(b)?)c" / exc strings pcre2] "ac");
-+  assert_equal "abc"
-+    (Pcre2.get_substring ([%match "ABC" / exc raw i pcre2] "abc") 0);
-+  assert_equal
-+    ("abc", Some "a", Some "b", Some "c")
-+    ([%match "(a)(b)(c)" / exc strings pcre2] "abc")
-+
-+let test_pcre2_selective_match ctxt =
-+  ();
-+  assert_equal ("abc", Some "b")
-+    ([%match "a(b)c" / exc strings (!0, 1) pcre2] "abc");
-+  assert_equal ("abc", "b")
-+    ([%match "a(b)c" / exc strings (!0, !1) pcre2] "abc");
-+  assert_equal "b" ([%match "a(b)c" / exc strings !1 pcre2] "abc");
-+  assert_equal
-+    (Some ("abc", "b"))
-+    ([%match "a(b)c" / strings (!0, !1) pcre2] "abc");
-+  assert_equal ("ac", None) ([%match "a(b)?c" / exc strings (!0, 1) pcre2] "ac");
-+  assert_raises Not_found (fun _ ->
-+      [%match "a(b)?c" / exc strings (!0, !1) pcre2] "ac");
-+  assert_equal None ([%match "a(b)?c" / strings (!0, !1) pcre2] "ac")
-+
-+let test_pcre2_search ctxt =
-+  ();
-+  assert_equal "abc" ([%match "abc" / exc strings pcre2] "zzzabc");
-+  assert_equal None ([%match "^abc" / strings pcre2] "zzzabc")
-+
-+let show_string_option = function
-+  | None -> "None"
-+  | Some s -> Printf.sprintf "Some %s" s
-+
-+let test_pcre2_single ctxt =
-+  let printer = show_string_option in
-+  ();
-+  assert_equal ~printer None ([%match ".+" / pcre2] "\n\n");
-+  assert_equal ~printer None ([%match ".+" / m pcre2 strings] "\n\n");
-+
-+  assert_equal ~printer None ([%match ".+" / pcre2 strings] "\n\n");
-+  assert_equal ~printer (Some "\n\n") ([%match ".+" / s pcre2 strings] "\n\n");
-+  assert_equal ~printer None ([%match ".+" / m pcre2 strings] "\n\n");
-+
-+  let printer x = x in
-+  ();
-+  assert_equal ~printer "\n\n" ([%match ".+" / s exc pcre2 strings] "\n\n");
-+  assert_equal ~printer "<<abc>>\ndef"
-+    ([%subst ".+" / {|<<$0>>|} / pcre2] "abc\ndef");
-+  assert_equal ~printer "<<abc\ndef>>"
-+    ([%subst ".+" / {|<<$0>>|} / s pcre2] "abc\ndef");
-+  assert_equal ~printer "<<abc>>\ndef"
-+    ([%subst ".+" / {|<<$0>>|} / m pcre2] "abc\ndef");
-+
-+  assert_equal ~printer "<<abc>>\ndef"
-+    ([%subst ".*" / {|<<$0>>|} / pcre2] "abc\ndef");
-+  assert_equal ~printer "<<abc>><<>>\n<<def>><<>>"
-+    ([%subst ".*" / {|<<$0>>|} / g pcre2] "abc\ndef");
-+  assert_equal ~printer "<<abc>>\n<<def>>"
-+    ([%subst ".+" / {|<<$0>>|} / g pcre2] "abc\ndef");
-+  assert_equal ~printer "<<abc>>a\nc<<aec>>"
-+    ([%subst "a.c" / {|<<$0>>|} / g pcre2] "abca\ncaec");
-+  assert_equal ~printer "<<abc>><<a\nc>><<aec>>"
-+    ([%subst "a.c" / {|<<$0>>|} / g s pcre2] "abca\ncaec")
-+
-+let test_pcre2_multiline ctxt =
-+  ();
-+  assert_equal (Some "bar") ([%match ".+$" / strings pcre2] "foo\nbar");
-+  assert_equal (Some "foo") ([%match ".+$" / m strings pcre2] "foo\nbar")
-+
-+let test_pcre2_simple_split ctxt =
-+  ();
-+  assert_equal [ "bb" ] ([%split "a" / pcre2] "bb")
-+
-+let test_pcre2_delim_split_raw ctxt =
-+  let open Pcre2 in
-+  ();
-+  assert_equal
-+    [ Delim "a"; Text "b"; Delim "a"; Text "b" ]
-+    ([%split "a" / pcre2 raw] "ababa");
-+  assert_equal
-+    [ Delim "a"; Text "b"; Delim "a"; Delim "a"; Text "b" ]
-+    ([%split "a" / pcre2 raw] "abaaba");
-+  assert_equal
-+    [
-+      Delim "a";
-+      NoGroup;
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "a";
-+      NoGroup;
-+    ]
-+    ([%split "a(c)?" / pcre2 raw] "abacba");
-+  assert_equal
-+    [
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+    ]
-+    ([%split "a(c)" / pcre2 raw] "acbacbac");
-+  assert_equal
-+    [
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+    ]
-+    ([%split "a(c)" / pcre2 raw] "acbacbac");
-+  assert_equal
-+    [
-+      Delim "a";
-+      NoGroup;
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "a";
-+      NoGroup;
-+    ]
-+    ([%split "a(c)?" / pcre2 raw] "abacba");
-+  assert_equal
-+    [ Text "ab"; Delim "x"; Group (1, "x"); NoGroup; Text "cd" ]
-+    ([%split {|(x)|(u)|} / raw pcre2] "abxcd");
-+  assert_equal
-+    [
-+      Text "ab";
-+      Delim "x";
-+      Group (1, "x");
-+      NoGroup;
-+      Text "cd";
-+      Delim "u";
-+      NoGroup;
-+      Group (2, "u");
-+    ]
-+    ([%split {|(x)|(u)|} / raw pcre2] "abxcdu")
-+
-+let test_pcre2_string_pattern ctxt =
-+  ();
-+  assert_equal "$b"
-+    ([%pattern {|$$$1|} / pcre2] ([%match "a(b)c" / exc pcre2 raw] "abc"));
-+  assert_equal "b"
-+    ([%pattern {|${01}|} / pcre2] ([%match "a(b)c" / exc pcre2 raw] "abc"));
-+  assert_equal "bx"
-+    (let s = "x" in
-+     [%pattern {|${01}${s}|} / pcre2] ([%match "a(b)c" / exc pcre2 raw] "abc"));
-+  assert_equal {|"bx|}
-+    (let s = "x" in
-+     [%pattern {|"${01}${s}|} / pcre2] ([%match "a(b)c" / exc pcre2 raw] "abc"));
-+  assert_equal {|"x|}
-+    (let s = "x" in
-+     [%pattern {|"${s}|} / pcre2])
-+
-+let test_pcre2_expr_pattern ctxt =
-+  ();
-+  assert_equal "abc"
-+    ([%pattern "$0$" / e pcre2] ([%match "abc" / exc pcre2 raw] "abc"));
-+  assert_equal "abcx"
-+    ([%pattern {|$0$ ^ "x"|} / e pcre2] ([%match "abc" / exc pcre2 raw] "abc"));
-+  assert_equal "abcx"
-+    (let x = "x" in
-+     [%pattern {|$0$ ^ x|} / e pcre2] ([%match "abc" / exc pcre2 raw] "abc"));
-+  assert_equal "x"
-+    (let x = "x" in
-+     [%pattern {|"" ^ x|} / e pcre2])
-+
-+let test_pcre2_subst ctxt =
-+  ();
-+  assert_equal "$b" ([%subst "a(b)c" / {|$$$1|} / pcre2] "abc");
-+  assert_equal "$b" ([%subst "A(B)C" / {|$$$1|} / i pcre2] "abc");
-+  assert_equal "$babc" ([%subst "A(B)C" / {|$$$1|} / i pcre2] "abcabc");
-+  assert_equal "$b$b" ([%subst "A(B)C" / {|$$$1|} / g i pcre2] "abcabc");
-+  assert_equal "$b$b" ([%subst "A(B)C" / {|"$" ^ $1$|} / e g i pcre2] "abcabc");
-+  assert_equal "$$" ([%subst "A(B)C" / {|"$"|} / e g i pcre2] "abcabc");
-+  assert_equal "$$" ([%subst "A(B)C" / {|$$|} / g i pcre2] "abcabc")
-+
-+let test_pcre2_ocamlfind_bits ctxt =
-+  ();
-+  assert_equal ~printer:show_string_option (Some "-syntax camlp5o ")
-+    (snd
-+       ([%match {|^\(\*\*pp (.*?)\*\)|} / exc strings pcre2]
-+          {|(**pp -syntax camlp5o *)
-+|}))
-+
-+let pcre2_envsubst envlookup s =
-+  let f s1 s2 =
-+    if s1 <> "" then envlookup s1
-+    else if s2 <> "" then envlookup s2
-+    else assert false
-+  in
-+
-+  [%subst {|(?:\$\(([^)]+)\)|\$\{([^}]+)\})|} / {| f $1$ $2$ |} / g e pcre2] s
-+
-+let test_pcre2_envsubst_via_replace ctxt =
-+  let f = function
-+    | "A" -> "res1"
-+    | "B" -> "res2"
-+    | _ -> failwith "unexpected arg in envsubst"
-+  in
-+  assert_equal "...res1...res2..." (pcre2_envsubst f {|...$(A)...${B}...|})
-+
-+let suite =
-+  "Test pa_ppx_regexp"
-+  >::: [
-+         "pcre2 simple_match" >:: test_pcre2_simple_match;
-+         "pcre2 selective_match" >:: test_pcre2_selective_match;
-+         "pcre2 search" >:: test_pcre2_search;
-+         "pcre2 single" >:: test_pcre2_single;
-+         "pcre2 multiline" >:: test_pcre2_multiline;
-+         "pcre2 simple_split" >:: test_pcre2_simple_split;
-+         "pcre2 delim_split raw" >:: test_pcre2_delim_split_raw;
-+         "pcre2 string_pattern" >:: test_pcre2_string_pattern;
-+         "pcre2 expr_pattern" >:: test_pcre2_expr_pattern;
-+         "pcre2 subst" >:: test_pcre2_subst;
-+         "pcre2 ocamlfind bits" >:: test_pcre2_ocamlfind_bits;
-+         "pcre2 envsubst via replace" >:: test_pcre2_envsubst_via_replace;
-+         "pcre only_regexps" >:: test_special_char_regexps;
-+       ]
-+
-+let _ = if not !Sys.interactive then run_test_tt_main suite else ()
-diff --git a/bundles/pcre2/pcre2-ocaml/pcre2.opam b/bundles/pcre2/pcre2-ocaml/pcre2.opam
-new file mode 100644
-index 000000000..f191fcd4d
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/pcre2.opam
-@@ -0,0 +1,37 @@
-+# This file is generated by dune, edit dune-project instead
-+opam-version: "2.0"
-+version: "8.0.4"
-+synopsis:
-+  "Bindings to the Perl Compatibility Regular Expressions library (version 2)"
-+description: """
-+pcre2-ocaml offers library functions for string pattern matching and
-+substitution, similar to the functionality offered by the Perl language."""
-+maintainer: ["Chet Murthy <chetsky@gmail.com>"]
-+authors: ["Markus Mottl <markus.mottl@gmail.com>"]
-+license: "LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception"
-+homepage: "https://github.com/camlp5/pcre2-ocaml"
-+bug-reports: "https://github.com/camlp5/pcre2-ocaml/issues"
-+depends: [
-+  "dune" {>= "2.7"}
-+  "ocaml" {>= "4.08"}
-+  "dune-compiledb"
-+  "dune-configurator"
-+  "conf-libpcre2-8" {build}
-+  "ounit2" {with-test}
-+  "odoc" {with-doc}
-+]
-+build: [
-+  ["dune" "subst"] {dev}
-+  [
-+    "dune"
-+    "build"
-+    "-p"
-+    name
-+    "-j"
-+    jobs
-+    "@install"
-+    "@runtest" {with-test}
-+    "@doc" {with-doc}
-+  ]
-+]
-+dev-repo: "git+https://github.com/camlp5/pcre2-ocaml.git"
-diff --git a/bundles/pcre2/pcre2-ocaml/test/dune b/bundles/pcre2/pcre2-ocaml/test/dune
-new file mode 100644
-index 000000000..af6fcfa5f
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/test/dune
-@@ -0,0 +1,14 @@
-+(test
-+ (name old_pcre2_tests)
-+ (modules Old_pcre2_tests)
-+ (libraries pcre2 ounit2))
-+
-+(test
-+ (name pcre2_tests)
-+ (modules Pcre2_tests)
-+ (libraries pcre2 ounit2))
-+
-+(env
-+ (dev
-+  (flags
-+   (:standard -w -27))))
-diff --git a/bundles/pcre2/pcre2-ocaml/test/old_pcre2_tests.ml b/bundles/pcre2/pcre2-ocaml/test/old_pcre2_tests.ml
-new file mode 100644
-index 000000000..e1f21e438
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/test/old_pcre2_tests.ml
-@@ -0,0 +1,24 @@
-+open OUnit2
-+open Pcre2
-+
-+let simple_test ctxt =
-+  assert_equal 0 0;
-+  assert_equal
-+    [ Text "ab"; Delim "x"; Group (1, "x"); NoGroup; Text "cd" ]
-+    (full_split ~pat:"(x)|(u)" "abxcd");
-+  assert_equal
-+    [
-+      Text "ab";
-+      Delim "x";
-+      Group (1, "x");
-+      NoGroup;
-+      Text "cd";
-+      Delim "u";
-+      NoGroup;
-+      Group (2, "u");
-+      Text "ef";
-+    ]
-+    (full_split ~pat:"(x)|(u)" "abxcduef")
-+
-+let suite = "Test pcre" >::: [ "simple_test" >:: simple_test ]
-+let _ = if not !Sys.interactive then run_test_tt_main suite else ()
-diff --git a/bundles/pcre2/pcre2-ocaml/test/pcre2_tests.ml b/bundles/pcre2/pcre2-ocaml/test/pcre2_tests.ml
-new file mode 100644
-index 000000000..fe600881a
---- /dev/null
-+++ b/bundles/pcre2/pcre2-ocaml/test/pcre2_tests.ml
-@@ -0,0 +1,746 @@
-+open OUnit2
-+(**pp -syntax camlp5o -package pa_ppx.deriving_plugins.std *)
-+
-+let test_special_char_regexps ctxt =
-+  ();
-+  assert_equal "\n"
-+    ((let __re__ = Pcre2.regexp ~flags:[ `DOTALL ] "\\n$" in
-+      fun __subj__ ->
-+        (fun __g__ -> Pcre2.get_substring __g__ 0)
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "\n");
-+  assert_equal ""
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[ `DOTALL ] "\\n+$")
-+       ~subst:(fun __g__ -> String.concat "" [])
-+       "\n\n")
-+
-+let test_pcre2_simple_match ctxt =
-+  ();
-+  assert_equal "abc"
-+    (Pcre2.get_substring
-+       ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc")
-+       0);
-+  assert_equal (Some "abc")
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "abc");
-+  assert_equal (Some "abc")
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "abc");
-+  assert_equal true
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ -> Pcre2.pmatch ~rex:__re__ __subj__)
-+       "abc");
-+  assert_equal false
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ -> Pcre2.pmatch ~rex:__re__ __subj__)
-+       "abd");
-+  assert_equal None
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "abd");
-+  assert_raises Not_found (fun () ->
-+      (let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+       fun __subj__ ->
-+         (fun __g__ -> Pcre2.get_substring __g__ 0)
-+           (Pcre2.exec ~rex:__re__ __subj__))
-+        "abd");
-+  assert_raises Not_found (fun () ->
-+      (let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+       fun __subj__ ->
-+         (fun __g__ -> Pcre2.get_substring __g__ 0)
-+           (Pcre2.exec ~rex:__re__ __subj__))
-+        "abd");
-+  assert_equal None
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "abd");
-+  assert_equal "abc"
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ ->
-+        (fun __g__ -> Pcre2.get_substring __g__ 0)
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "abc");
-+  assert_equal ("abc", Some "b")
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+      fun __subj__ ->
-+        (fun __g__ ->
-+          ( Pcre2.get_substring __g__ 0,
-+            try Some (Pcre2.get_substring __g__ 1) with Not_found -> None ))
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "abc");
-+  assert_equal ("ac", None)
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(?:(b)?)c" in
-+      fun __subj__ ->
-+        (fun __g__ ->
-+          ( Pcre2.get_substring __g__ 0,
-+            try Some (Pcre2.get_substring __g__ 1) with Not_found -> None ))
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "ac");
-+  assert_equal "abc"
-+    (Pcre2.get_substring
-+       ((let __re__ = Pcre2.regexp ~flags:[ `CASELESS ] "ABC" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc")
-+       0);
-+  assert_equal
-+    ("abc", Some "a", Some "b", Some "c")
-+    ((let __re__ = Pcre2.regexp ~flags:[] "(a)(b)(c)" in
-+      fun __subj__ ->
-+        (fun __g__ ->
-+          ( Pcre2.get_substring __g__ 0,
-+            (try Some (Pcre2.get_substring __g__ 1) with Not_found -> None),
-+            (try Some (Pcre2.get_substring __g__ 2) with Not_found -> None),
-+            try Some (Pcre2.get_substring __g__ 3) with Not_found -> None ))
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "abc")
-+
-+let test_pcre2_selective_match ctxt =
-+  ();
-+  assert_equal ("abc", Some "b")
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+      fun __subj__ ->
-+        (fun __g__ ->
-+          ( Pcre2.get_substring __g__ 0,
-+            try Some (Pcre2.get_substring __g__ 1) with Not_found -> None ))
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "abc");
-+  assert_equal ("abc", "b")
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+      fun __subj__ ->
-+        (fun __g__ ->
-+          (Pcre2.get_substring __g__ 0, Pcre2.get_substring __g__ 1))
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "abc");
-+  assert_equal "b"
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+      fun __subj__ ->
-+        (fun __g__ -> Pcre2.get_substring __g__ 1)
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "abc");
-+  assert_equal
-+    (Some ("abc", "b"))
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ ->
-+              (Pcre2.get_substring __g__ 0, Pcre2.get_substring __g__ 1))
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "abc");
-+  assert_equal ("ac", None)
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)?c" in
-+      fun __subj__ ->
-+        (fun __g__ ->
-+          ( Pcre2.get_substring __g__ 0,
-+            try Some (Pcre2.get_substring __g__ 1) with Not_found -> None ))
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "ac");
-+  assert_raises Not_found (fun _ ->
-+      (let __re__ = Pcre2.regexp ~flags:[] "a(b)?c" in
-+       fun __subj__ ->
-+         (fun __g__ ->
-+           (Pcre2.get_substring __g__ 0, Pcre2.get_substring __g__ 1))
-+           (Pcre2.exec ~rex:__re__ __subj__))
-+        "ac");
-+  assert_equal None
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(b)?c" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ ->
-+              (Pcre2.get_substring __g__ 0, Pcre2.get_substring __g__ 1))
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "ac")
-+
-+let test_pcre2_search ctxt =
-+  ();
-+  assert_equal "abc"
-+    ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+      fun __subj__ ->
-+        (fun __g__ -> Pcre2.get_substring __g__ 0)
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "zzzabc");
-+  assert_equal None
-+    ((let __re__ = Pcre2.regexp ~flags:[] "^abc" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "zzzabc")
-+
-+let show_string_option = function
-+  | None -> "None"
-+  | Some s -> Printf.sprintf "Some %s" s
-+
-+let test_pcre2_single ctxt =
-+  let printer = show_string_option in
-+  ();
-+  assert_equal ~printer None
-+    ((let __re__ = Pcre2.regexp ~flags:[] ".+" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "\n\n");
-+  assert_equal ~printer None
-+    ((let __re__ = Pcre2.regexp ~flags:[ `MULTILINE ] ".+" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "\n\n");
-+  assert_equal ~printer None
-+    ((let __re__ = Pcre2.regexp ~flags:[] ".+" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "\n\n");
-+  assert_equal ~printer (Some "\n\n")
-+    ((let __re__ = Pcre2.regexp ~flags:[ `DOTALL ] ".+" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "\n\n");
-+  assert_equal ~printer None
-+    ((let __re__ = Pcre2.regexp ~flags:[ `MULTILINE ] ".+" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "\n\n");
-+  let printer x = x in
-+  ();
-+  assert_equal ~printer "\n\n"
-+    ((let __re__ = Pcre2.regexp ~flags:[ `DOTALL ] ".+" in
-+      fun __subj__ ->
-+        (fun __g__ -> Pcre2.get_substring __g__ 0)
-+          (Pcre2.exec ~rex:__re__ __subj__))
-+       "\n\n");
-+  assert_equal ~printer "<<abc>>\ndef"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[] ".+")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abc\ndef");
-+  assert_equal ~printer "<<abc\ndef>>"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[ `DOTALL ] ".+")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abc\ndef");
-+  assert_equal ~printer "<<abc>>\ndef"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[ `MULTILINE ] ".+")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abc\ndef");
-+  assert_equal ~printer "<<abc>>\ndef"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[] ".*")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abc\ndef");
-+  assert_equal ~printer "<<abc>><<>>\n<<def>><<>>"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[] ".*")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abc\ndef");
-+  assert_equal ~printer "<<abc>>\n<<def>>"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[] ".+")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abc\ndef");
-+  assert_equal ~printer "<<abc>>a\nc<<aec>>"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[] "a.c")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abca\ncaec");
-+  assert_equal ~printer "<<abc>><<a\nc>><<aec>>"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[ `DOTALL ] "a.c")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "<<";
-+             (match Pcre2.get_substring __g__ 0 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+             ">>";
-+           ])
-+       "abca\ncaec")
-+
-+let test_pcre2_multiline ctxt =
-+  ();
-+  assert_equal (Some "bar")
-+    ((let __re__ = Pcre2.regexp ~flags:[] ".+$" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "foo\nbar");
-+  assert_equal (Some "foo")
-+    ((let __re__ = Pcre2.regexp ~flags:[ `MULTILINE ] ".+$" in
-+      fun __subj__ ->
-+        match
-+          Option.map
-+            (fun __g__ -> Pcre2.get_substring __g__ 0)
-+            (try Some (Pcre2.exec ~rex:__re__ __subj__) with Not_found -> None)
-+        with
-+        | exception Not_found -> None
-+        | rv -> rv)
-+       "foo\nbar")
-+
-+let test_pcre2_simple_split ctxt =
-+  ();
-+  assert_equal [ "bb" ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a" in
-+      fun __subj__ -> Pcre2.split ~rex:__re__ __subj__)
-+       "bb")
-+
-+let test_pcre2_delim_split_raw ctxt =
-+  let open Pcre2 in
-+  ();
-+  assert_equal
-+    [ Delim "a"; Text "b"; Delim "a"; Text "b" ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "ababa");
-+  assert_equal
-+    [ Delim "a"; Text "b"; Delim "a"; Delim "a"; Text "b" ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "abaaba");
-+  assert_equal
-+    [
-+      Delim "a";
-+      NoGroup;
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "a";
-+      NoGroup;
-+    ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(c)?" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "abacba");
-+  assert_equal
-+    [
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+    ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(c)" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "acbacbac");
-+  assert_equal
-+    [
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+    ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(c)" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "acbacbac");
-+  assert_equal
-+    [
-+      Delim "a";
-+      NoGroup;
-+      Text "b";
-+      Delim "ac";
-+      Group (1, "c");
-+      Text "b";
-+      Delim "a";
-+      NoGroup;
-+    ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "a(c)?" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "abacba");
-+  assert_equal
-+    [ Text "ab"; Delim "x"; Group (1, "x"); NoGroup; Text "cd" ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "(x)|(u)" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "abxcd");
-+  assert_equal
-+    [
-+      Text "ab";
-+      Delim "x";
-+      Group (1, "x");
-+      NoGroup;
-+      Text "cd";
-+      Delim "u";
-+      NoGroup;
-+      Group (2, "u");
-+    ]
-+    ((let __re__ = Pcre2.regexp ~flags:[] "(x)|(u)" in
-+      fun __subj__ -> Pcre2.full_split ~rex:__re__ __subj__)
-+       "abxcdu")
-+
-+let test_pcre2_string_pattern ctxt =
-+  ();
-+  assert_equal "$b"
-+    ((fun __g__ ->
-+       String.concat ""
-+         [
-+           "$";
-+           "";
-+           (match Pcre2.get_substring __g__ 1 with
-+           | exception Not_found -> ""
-+           | s -> s);
-+         ])
-+       ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "b"
-+    ((fun __g__ ->
-+       String.concat ""
-+         [
-+           (match Pcre2.get_substring __g__ 01 with
-+           | exception Not_found -> ""
-+           | s -> s);
-+         ])
-+       ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "bx"
-+    (let s = "x" in
-+     (fun __g__ ->
-+       String.concat ""
-+         [
-+           (match Pcre2.get_substring __g__ 01 with
-+           | exception Not_found -> ""
-+           | s -> s);
-+           "";
-+           s;
-+         ])
-+       ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "\"bx"
-+    (let s = "x" in
-+     (fun __g__ ->
-+       String.concat ""
-+         [
-+           "\"";
-+           (match Pcre2.get_substring __g__ 01 with
-+           | exception Not_found -> ""
-+           | s -> s);
-+           "";
-+           s;
-+         ])
-+       ((let __re__ = Pcre2.regexp ~flags:[] "a(b)c" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "\"x"
-+    (let s = "x" in
-+     String.concat "" [ "\""; s ])
-+
-+let test_pcre2_expr_pattern ctxt =
-+  ();
-+  assert_equal "abc"
-+    ((fun __g__ ->
-+       match Pcre2.get_substring __g__ 0 with
-+       | exception Not_found -> ""
-+       | s -> s)
-+       ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "abcx"
-+    ((fun __g__ ->
-+       (match Pcre2.get_substring __g__ 0 with
-+       | exception Not_found -> ""
-+       | s -> s)
-+       ^ "x")
-+       ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "abcx"
-+    (let x = "x" in
-+     (fun __g__ ->
-+       (match Pcre2.get_substring __g__ 0 with
-+       | exception Not_found -> ""
-+       | s -> s)
-+       ^ x)
-+       ((let __re__ = Pcre2.regexp ~flags:[] "abc" in
-+         fun __subj__ -> Pcre2.exec ~rex:__re__ __subj__)
-+          "abc"));
-+  assert_equal "x"
-+    (let x = "x" in
-+     "" ^ x)
-+
-+let test_pcre2_subst ctxt =
-+  ();
-+  assert_equal "$b"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[] "a(b)c")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "$";
-+             "";
-+             (match Pcre2.get_substring __g__ 1 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+           ])
-+       "abc");
-+  assert_equal "$b"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[ `CASELESS ] "A(B)C")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "$";
-+             "";
-+             (match Pcre2.get_substring __g__ 1 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+           ])
-+       "abc");
-+  assert_equal "$babc"
-+    (Pcre2.substitute_substrings_first
-+       ~rex:(Pcre2.regexp ~flags:[ `CASELESS ] "A(B)C")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "$";
-+             "";
-+             (match Pcre2.get_substring __g__ 1 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+           ])
-+       "abcabc");
-+  assert_equal "$b$b"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[ `CASELESS ] "A(B)C")
-+       ~subst:(fun __g__ ->
-+         String.concat ""
-+           [
-+             "$";
-+             "";
-+             (match Pcre2.get_substring __g__ 1 with
-+             | exception Not_found -> ""
-+             | s -> s);
-+           ])
-+       "abcabc");
-+  assert_equal "$b$b"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[ `CASELESS ] "A(B)C")
-+       ~subst:(fun __g__ ->
-+         "$"
-+         ^
-+         match Pcre2.get_substring __g__ 1 with
-+         | exception Not_found -> ""
-+         | s -> s)
-+       "abcabc");
-+  assert_equal "$$"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[ `CASELESS ] "A(B)C")
-+       ~subst:(fun __g__ -> "$")
-+       "abcabc");
-+  assert_equal "$$"
-+    (Pcre2.substitute_substrings
-+       ~rex:(Pcre2.regexp ~flags:[ `CASELESS ] "A(B)C")
-+       ~subst:(fun __g__ -> String.concat "" [ "$" ])
-+       "abcabc")
-+
-+let test_pcre2_ocamlfind_bits ctxt =
-+  ();
-+  assert_equal ~printer:show_string_option (Some "-syntax camlp5o ")
-+    (snd
-+       ((let __re__ = Pcre2.regexp ~flags:[] "^\\(\\*\\*pp (.*?)\\*\\)" in
-+         fun __subj__ ->
-+           (fun __g__ ->
-+             ( Pcre2.get_substring __g__ 0,
-+               try Some (Pcre2.get_substring __g__ 1) with Not_found -> None ))
-+             (Pcre2.exec ~rex:__re__ __subj__))
-+          "(**pp -syntax camlp5o *)\n"))
-+
-+let pcre2_envsubst envlookup s =
-+  let f s1 s2 =
-+    if s1 <> "" then envlookup s1
-+    else if s2 <> "" then envlookup s2
-+    else assert false
-+  in
-+  Pcre2.substitute_substrings
-+    ~rex:(Pcre2.regexp ~flags:[] "(?:\\$\\(([^)]+)\\)|\\$\\{([^}]+)\\})")
-+    ~subst:(fun __g__ ->
-+      f
-+        (match Pcre2.get_substring __g__ 1 with
-+        | exception Not_found -> ""
-+        | s -> s)
-+        (match Pcre2.get_substring __g__ 2 with
-+        | exception Not_found -> ""
-+        | s -> s))
-+    s
-+
-+let test_pcre2_envsubst_via_replace ctxt =
-+  let f = function
-+    | "A" -> "res1"
-+    | "B" -> "res2"
-+    | _ -> failwith "unexpected arg in envsubst"
-+  in
-+  assert_equal "...res1...res2..." (pcre2_envsubst f "...$(A)...${B}...")
-+
-+let bad_pattern ctxt =
-+  let open Pcre2 in
-+  try
-+    ignore (regexp "?");
-+    assert_failure "Regex should fail to parse"
-+  with Error (BadPattern (s, _)) ->
-+    assert_bool
-+      "String contains a zero byte. In 8-bit mode this indicates an error in \
-+       the creation of the error message since strings created by PCRE2 should \
-+       be null terminated."
-+      (not @@ String.exists (fun c -> c = '\000') s)
-+
-+let suite =
-+  "Test pa_ppx_regexp"
-+  >::: [
-+         "pcre2 simple_match" >:: test_pcre2_simple_match;
-+         "pcre2 selective_match" >:: test_pcre2_selective_match;
-+         "pcre2 search" >:: test_pcre2_search;
-+         "pcre2 single" >:: test_pcre2_single;
-+         "pcre2 multiline" >:: test_pcre2_multiline;
-+         "pcre2 simple_split" >:: test_pcre2_simple_split;
-+         "pcre2 delim_split raw" >:: test_pcre2_delim_split_raw;
-+         "pcre2 string_pattern" >:: test_pcre2_string_pattern;
-+         "pcre2 expr_pattern" >:: test_pcre2_expr_pattern;
-+         "pcre2 subst" >:: test_pcre2_subst;
-+         "pcre2 ocamlfind bits" >:: test_pcre2_ocamlfind_bits;
-+         "pcre2 envsubst via replace" >:: test_pcre2_envsubst_via_replace;
-+         "pcre only_regexps" >:: test_special_char_regexps;
-+         "bad_pattern" >:: bad_pattern;
-+       ]
-+
-+let _ = if not !Sys.interactive then run_test_tt_main suite
--- 
-2.52.0
-

diff --git a/0005-rename-some-bundled-pcre2-files-to-be-input-files.patch b/0005-rename-some-bundled-pcre2-files-to-be-input-files.patch
deleted file mode 100644
index fe449c8..0000000
--- a/0005-rename-some-bundled-pcre2-files-to-be-input-files.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From ba09b5d2c8c71ba64ac520367401c58555b48190 Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Wed, 14 Jan 2026 11:34:57 +0100
-Subject: [PATCH 5/9] rename some bundled pcre2 files to be input files
-
-(cherry picked from commit a616d0a2498da843d4cde33eea81ec9967689363)
----
- bundles/pcre2/pcre2-ocaml/lib/{pcre2.ml => pcre2.ml.in}           | 0
- bundles/pcre2/pcre2-ocaml/lib/{pcre2_stubs.c => pcre2_stubs.c.in} | 0
- 2 files changed, 0 insertions(+), 0 deletions(-)
- rename bundles/pcre2/pcre2-ocaml/lib/{pcre2.ml => pcre2.ml.in} (100%)
- rename bundles/pcre2/pcre2-ocaml/lib/{pcre2_stubs.c => pcre2_stubs.c.in} (100%)
-
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/pcre2.ml b/bundles/pcre2/pcre2-ocaml/lib/pcre2.ml.in
-similarity index 100%
-rename from bundles/pcre2/pcre2-ocaml/lib/pcre2.ml
-rename to bundles/pcre2/pcre2-ocaml/lib/pcre2.ml.in
-diff --git a/bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c b/bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c.in
-similarity index 100%
-rename from bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c
-rename to bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c.in
--- 
-2.52.0
-

diff --git a/0006-add-.gitignore-in-pcre2-bundle-to-exclude-generated-.patch b/0006-add-.gitignore-in-pcre2-bundle-to-exclude-generated-.patch
deleted file mode 100644
index 8149a3b..0000000
--- a/0006-add-.gitignore-in-pcre2-bundle-to-exclude-generated-.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 2e34e86bda23cabd7d278a2aae1f420da44aa50e Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Wed, 14 Jan 2026 11:38:08 +0100
-Subject: [PATCH 6/9] add .gitignore in pcre2 bundle to exclude generated files
-
-(cherry picked from commit 0bb085307618652f79cc7a688a66d37d881b26ad)
----
- bundles/pcre2/.gitignore | 2 ++
- 1 file changed, 2 insertions(+)
- create mode 100644 bundles/pcre2/.gitignore
-
-diff --git a/bundles/pcre2/.gitignore b/bundles/pcre2/.gitignore
-new file mode 100644
-index 000000000..81438e117
---- /dev/null
-+++ b/bundles/pcre2/.gitignore
-@@ -0,0 +1,2 @@
-+pcre2-ocaml/lib/pcre2.ml
-+pcre2-ocaml/lib/pcre2_stubs.c
-\ No newline at end of file
--- 
-2.52.0
-

diff --git a/0007-rename-update-pcre-bundle-Makefile-to-reflect-bundle.patch b/0007-rename-update-pcre-bundle-Makefile-to-reflect-bundle.patch
deleted file mode 100644
index cf35ec5..0000000
--- a/0007-rename-update-pcre-bundle-Makefile-to-reflect-bundle.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 2ea3e988228e8b27966fea07b718efffc7d82d5e Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Wed, 14 Jan 2026 12:04:36 +0100
-Subject: [PATCH 7/9] rename/update pcre bundle Makefile to reflect bundle
- changes
-
-(cherry picked from commit cb87f4511db9321909c157aee9a68a52d9b6619c)
----
- bundles/{pcre => pcre2}/Makefile | 18 +++++++++---------
- 1 file changed, 9 insertions(+), 9 deletions(-)
- rename bundles/{pcre => pcre2}/Makefile (60%)
-
-diff --git a/bundles/pcre/Makefile b/bundles/pcre2/Makefile
-similarity index 60%
-rename from bundles/pcre/Makefile
-rename to bundles/pcre2/Makefile
-index 0db00b087..e1aed9865 100644
---- a/bundles/pcre/Makefile
-+++ b/bundles/pcre2/Makefile
-@@ -1,14 +1,14 @@
- # This Makefile serves as a wrapper to bundle the
--# pcre module without modifications.
-+# pcre2 module without modifications.
- 
--MODULES=pcre
--OBJS=pcre
--INTERFACES=pcre
--C_OBJS=pcre
--ARCHIVE=pcre
--LIBRARY=pcre
--C_LIBS=pcre
--SRC_DIR=pcre-ocaml/src
-+MODULES=pcre2
-+OBJS=pcre2
-+INTERFACES=pcre2
-+C_OBJS=pcre2
-+ARCHIVE=pcre2
-+LIBRARY=pcre2
-+C_LIBS=pcre2-8
-+SRC_DIR=pcre2-ocaml/lib
- 
- OCAMLFLAGS+=-I $(STDCOMPATDIR)
- 
--- 
-2.52.0
-

diff --git a/0008-configure.ac-use-pcre2-ocaml-lib-folder-to-reflect-n.patch b/0008-configure.ac-use-pcre2-ocaml-lib-folder-to-reflect-n.patch
deleted file mode 100644
index c3cf2a0..0000000
--- a/0008-configure.ac-use-pcre2-ocaml-lib-folder-to-reflect-n.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From c82439140c22419d7eec30a94cc244e20d1fe41e Mon Sep 17 00:00:00 2001
-From: Victor Gambier <victor.gambier@inria.fr>
-Date: Tue, 20 Jan 2026 15:44:47 +0100
-Subject: [PATCH 8/9] configure.ac: use pcre2-ocaml/lib folder to reflect new
- bundle structure
-
-(cherry picked from commit b231de0db3f9513f6ea936caea5428fe627af1b9)
----
- configure.ac | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index cd9005a87..aea7e35e0 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -594,8 +594,8 @@ AS_IF([test "$MAKE_pcre2"],
-      AC_SUBST([noalloc], [[[@@noalloc]]])
-      AC_SUBST([untagged], [[[@untagged]]])])
-   AC_CONFIG_FILES([
--    bundles/pcre/pcre-ocaml/src/pcre.ml
--    bundles/pcre/pcre-ocaml/src/pcre_stubs.c
-+    bundles/pcre2/pcre2-ocaml/lib/pcre2.ml
-+    bundles/pcre2/pcre2-ocaml/lib/pcre2_stubs.c
-   ])])
- 
- dnl
--- 
-2.52.0
-

diff --git a/0009-replace-obsolescent-egrep-with-grep-E.patch b/0009-replace-obsolescent-egrep-with-grep-E.patch
deleted file mode 100644
index fdec4d1..0000000
--- a/0009-replace-obsolescent-egrep-with-grep-E.patch
+++ /dev/null
@@ -1,88 +0,0 @@
-From 18fc421c9af69d085e6e1c95e9d5cf36a2ba7011 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Christoph=20B=C3=B6hmwalder?=
- <christoph.boehmwalder@linbit.com>
-Date: Mon, 2 Mar 2026 16:44:10 +0100
-Subject: [PATCH 9/9] replace obsolescent egrep with grep -E
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-egrep has been deprecated since GNU grep 3.8 (Sep 2022) and prints a
-warning to stderr on every invocation. Replace all occurrences with
-the POSIX-standard grep -E.
-
-Signed-off-by: Christoph Böhmwalder <christoph.boehmwalder@linbit.com>
-(cherry picked from commit 233b5ceb1d5a701fb270ebdf0a9bd6be0a6ce53b)
----
- cocci.ml                           | 2 +-
- docs/manual/Makefile               | 4 ++--
- parsing_cocci/patch_diff.ml        | 4 ++--
- scripts/stat_directory_complete.pl | 2 +-
- 4 files changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/cocci.ml b/cocci.ml
-index 124156856..e769d5fe4 100644
---- a/cocci.ml
-+++ b/cocci.ml
-@@ -531,7 +531,7 @@ let worth_trying2 cfiles (tokens,_,query,_) =
- 
-       ) in
-       let com =
--	Printf.sprintf "egrep -q '(%s)' %s"
-+	Printf.sprintf "grep -E -q '(%s)' %s"
- 	  (String.concat "|" tokens)
- 	  (String.concat " " (List.map fst cfiles)) in
-       (match Sys.command com with
-diff --git a/docs/manual/Makefile b/docs/manual/Makefile
-index 7a0e001a9..b0ed58019 100644
---- a/docs/manual/Makefile
-+++ b/docs/manual/Makefile
-@@ -63,8 +63,8 @@ distclean:: clean
- #
- #%.pdf:	%.tex
- #	    $(PDFLATEX) $<
--#	    if egrep -s '$(RERUN)' $*.log ;then $(PDFLATEX) $<; fi
--#	    if egrep -s '$(RERUN)' $*.log ;then $(PDFLATEX) $<; fi
-+#	    if grep -E -s '$(RERUN)' $*.log ;then $(PDFLATEX) $<; fi
-+#	    if grep -E -s '$(RERUN)' $*.log ;then $(PDFLATEX) $<; fi
- 
- ##############################################################################
- # Html version
-diff --git a/parsing_cocci/patch_diff.ml b/parsing_cocci/patch_diff.ml
-index d84f3ad7c..88bd4077c 100755
---- a/parsing_cocci/patch_diff.ml
-+++ b/parsing_cocci/patch_diff.ml
-@@ -82,7 +82,7 @@ let rec mlines lines =
- let final_info dir =
-   let git_root = get_root dir in
-   let git_read_command =
--    "cd " ^ git_root ^ " && git diff " ^ dir ^ " | egrep '^+++|^@'" in
-+    "cd " ^ git_root ^ " && git diff " ^ dir ^ " | grep -E '^+++|^@'" in
-   let list_diff =
-     reorg dir git_root (mlines (Common.cmd_to_list git_read_command)) in
-   list_diff
-@@ -103,7 +103,7 @@ let final_patch_info dir startid endid =
-       if recent
-       then "--merge-base"
-       else "" in
--    Printf.sprintf " cd %s && git diff %s %s %s | egrep '^+++|^@'"
-+    Printf.sprintf " cd %s && git diff %s %s %s | grep -E '^+++|^@'"
-       git_root extra startid endid in
-   let list_diff =
-     reorg dir git_root (mlines (Common.cmd_to_list git_read_command)) in
-diff --git a/scripts/stat_directory_complete.pl b/scripts/stat_directory_complete.pl
-index f7894d70a..9caf5a601 100755
---- a/scripts/stat_directory_complete.pl
-+++ b/scripts/stat_directory_complete.pl
-@@ -164,7 +164,7 @@ if(-e "gitinfo") {
-   my $nodateyet = 1;
- 
-   while(<TMP>) {
--    #can also do: egrep "^Author" gitinfo | sort | uniq | wc -l
-+    #can also do: grep -E "^Author" gitinfo | sort | uniq | wc -l
-     if (/^Author: (.*)/) {
-       $h->{$1}++;
-     }
--- 
-2.52.0
-

diff --git a/coccinelle.spec b/coccinelle.spec
index 93eb66f..dc8c1bd 100644
--- a/coccinelle.spec
+++ b/coccinelle.spec
@@ -3,10 +3,10 @@ ExcludeArch: %{ix86}
 
 #global forgeurl https://github.com/coccinelle/coccinelle
 %global forgeurl https://gitlab.inria.fr/coccinelle/coccinelle
-%global tag 1.3.1
+%global tag 1.3.3
 #global commit 09b475bb3dd2b29c6bd904cc455d4c25c6641649
 #global date   20251118
-Version:       1.3.1
+Version:       1.3.3
 %forgemeta
 
 # Build the documentation on Fedora only.
@@ -23,7 +23,7 @@ Version:       1.3.1
 %endif
 
 Name:           coccinelle
-Release:        10%{?dist}
+Release:        1%{?dist}
 Summary:        Semantic patching for Linux (spatch)
 
 License:        GPL-2.0-only
@@ -35,19 +35,6 @@ Source0:        %{forgesource}
 Source1:        test.c
 Source2:        testpy.cocci
 
-# RWMJ: I backported some patches for ocaml-pcre2 support from upstream.
-# They can be found here:
-# https://github.com/rwmjones/coccinelle/tree/fedora-1.3.1
-Patch:          0001-replace-pcre-with-pcre2.patch
-Patch:          0002-use-pcre2-instead-of-pcre-in-some-more-places.patch
-Patch:          0003-replace-pcre-with-pcre2-in-install.txt-instructions.patch
-Patch:          0004-replace-pcre-bundle-with-pcre2-bundle.patch
-Patch:          0005-rename-some-bundled-pcre2-files-to-be-input-files.patch
-Patch:          0006-add-.gitignore-in-pcre2-bundle-to-exclude-generated-.patch
-Patch:          0007-rename-update-pcre-bundle-Makefile-to-reflect-bundle.patch
-Patch:          0008-configure.ac-use-pcre2-ocaml-lib-folder-to-reflect-n.patch
-Patch:          0009-replace-obsolescent-egrep-with-grep-E.patch
-
 BuildRequires:  autoconf
 BuildRequires:  automake
 BuildRequires:  python3-devel
@@ -300,6 +287,10 @@ $spatch --sp-file %{SOURCE2} %{SOURCE1}
 
 
 %changelog
+* Fri Sep 04 2026 Richard W.M. Jones <rjones@redhat.com> - 1.3.3-1
+- New version 1.3.3 (RHBZ#2519492)
+- Drop ocaml-pcre2, egrep patches which are now upstream.
+
 * Wed Jul 22 2026 Python Maint <python-maint@redhat.com> - 1.3.1-10
 - Rebuilt for Python 3.15.0b4 ABI change
 

diff --git a/sources b/sources
index 9fac5c9..7daeeb9 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (coccinelle-1.3.1.tar.bz2) = 924aea43b4e927b6a1d0775e064b697abeeb4de0dd1dec8885ccdf1494d65336802a78d281f8e9179db625a8857d10e6585a28570e6f563273c2f31736083715
+SHA512 (coccinelle-1.3.3.tar.bz2) = 4ebd46faf15d8d9fffd9475f5d675deeab13a884b6210a0c8be03457843deec65dc7c33a2d9a29b3dd99e4454488a7abdbe42a30e3ab3e1d51e1390d9e578c42

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-04 10:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-04 10:20 [rpms/coccinelle] rawhide: New version 1.3.3 (RHBZ#2519492) Richard W.M. Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox