aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/pcre2-10.32
diff options
context:
space:
mode:
authorDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2019-04-06 20:15:36 +0200
committerDavid Monniaux <david.monniaux@univ-grenoble-alpes.fr>2019-04-06 20:15:36 +0200
commit4ddd71912c27ac88f4a2c82c0aa5046253923adb (patch)
treeaed36853954980341d7a837577d176f42d2406c7 /test/monniaux/pcre2-10.32
parent9674df32359b7286379ad7f95e7ff54e9cf895da (diff)
downloadcompcert-kvx-4ddd71912c27ac88f4a2c82c0aa5046253923adb.tar.gz
compcert-kvx-4ddd71912c27ac88f4a2c82c0aa5046253923adb.zip
tests with PCRE2 (regular expression library)
Diffstat (limited to 'test/monniaux/pcre2-10.32')
-rw-r--r--test/monniaux/pcre2-10.32/Makefile41
-rw-r--r--test/monniaux/pcre2-10.32/bsp_frequency.c1
-rw-r--r--test/monniaux/pcre2-10.32/config.h366
-rw-r--r--test/monniaux/pcre2-10.32/pcre2.h974
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_auto_possess.c1322
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_chartables.c198
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_compile.c9921
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_config.c246
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_context.c476
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_convert.c1182
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_dfa_match.c3864
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_error.c334
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_extuni.c148
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_find_bracket.c219
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_internal.h1945
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_intmodedep.h918
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_jit_compile.c12708
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_jit_match.c189
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_jit_misc.c227
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_maketables.c150
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_match.c6860
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_match_data.c147
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_newline.c243
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_ord2utf.c120
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_pattern_info.c432
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_printint.c832
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_serialize.c286
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_string_utils.c237
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_study.c1635
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_substitute.c885
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_substring.c547
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_tables.c827
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_ucd.c4189
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_ucp.h288
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_valid_utf.c398
-rw-r--r--test/monniaux/pcre2-10.32/pcre2_xclass.c271
-rw-r--r--test/monniaux/pcre2-10.32/pcre2posix.c375
-rw-r--r--test/monniaux/pcre2-10.32/pcre2posix.h151
-rw-r--r--test/monniaux/pcre2-10.32/pcre2test.c8791
39 files changed, 62943 insertions, 0 deletions
diff --git a/test/monniaux/pcre2-10.32/Makefile b/test/monniaux/pcre2-10.32/Makefile
new file mode 100644
index 00000000..317819ae
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/Makefile
@@ -0,0 +1,41 @@
+CC=../../../ccomp
+CFLAGS=-O3 -Wall
+
+CFILES = \
+ pcre2_auto_possess.c \
+ pcre2_chartables.c \
+ pcre2_compile.c \
+ pcre2_config.c \
+ pcre2_context.c \
+ pcre2_convert.c \
+ pcre2_dfa_match.c \
+ pcre2_error.c \
+ pcre2_extuni.c \
+ pcre2_find_bracket.c \
+ pcre2_jit_compile.c \
+ pcre2_maketables.c \
+ pcre2_match.c \
+ pcre2_match_data.c \
+ pcre2_newline.c \
+ pcre2_ord2utf.c \
+ pcre2_pattern_info.c \
+ pcre2_serialize.c \
+ pcre2_string_utils.c \
+ pcre2_study.c \
+ pcre2_substitute.c \
+ pcre2_substring.c \
+ pcre2_tables.c \
+ pcre2_ucd.c \
+ pcre2_valid_utf.c \
+ pcre2_xclass.c \
+ pcre2posix.c \
+ pcre2test.c \
+ bsp_frequency.c
+
+HFILES = config.h pcre2_internal.h pcre2posix.h \
+pcre2.h pcre2_intmodedep.h pcre2_ucp.h
+
+CFLAGS += -DHAVE_CONFIG_H
+
+pcre2test: $(CFILES) $(HFILES)
+ $(CC) $(CFLAGS) -o $@ -DPCRE2_CODE_UNIT_WIDTH=8 $(CFILES)
diff --git a/test/monniaux/pcre2-10.32/bsp_frequency.c b/test/monniaux/pcre2-10.32/bsp_frequency.c
new file mode 100644
index 00000000..058739e2
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/bsp_frequency.c
@@ -0,0 +1 @@
+unsigned long __bsp_frequency = 400000000;
diff --git a/test/monniaux/pcre2-10.32/config.h b/test/monniaux/pcre2-10.32/config.h
new file mode 100644
index 00000000..41061058
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/config.h
@@ -0,0 +1,366 @@
+/* src/config.h. Generated from config.h.in by configure. */
+/* src/config.h.in. Generated from configure.ac by autoheader. */
+
+/* PCRE2 is written in Standard C, but there are a few non-standard things it
+can cope with, allowing it to run on SunOS4 and other "close to standard"
+systems.
+
+In environments that support the GNU autotools, config.h.in is converted into
+config.h by the "configure" script. In environments that use CMake,
+config-cmake.in is converted into config.h. If you are going to build PCRE2 "by
+hand" without using "configure" or CMake, you should copy the distributed
+config.h.generic to config.h, and edit the macro definitions to be the way you
+need them. You must then add -DHAVE_CONFIG_H to all of your compile commands,
+so that config.h is included at the start of every source.
+
+Alternatively, you can avoid editing by using -D on the compiler command line
+to set the macro values. In this case, you do not have to set -DHAVE_CONFIG_H,
+but if you do, default values will be taken from config.h for non-boolean
+macros that are not defined on the command line.
+
+Boolean macros such as HAVE_STDLIB_H and SUPPORT_PCRE2_8 should either be
+defined (conventionally to 1) for TRUE, and not defined at all for FALSE. All
+such macros are listed as a commented #undef in config.h.generic. Macros such
+as MATCH_LIMIT, whose actual value is relevant, have defaults defined, but are
+surrounded by #ifndef/#endif lines so that the value can be overridden by -D.
+
+PCRE2 uses memmove() if HAVE_MEMMOVE is defined; otherwise it uses bcopy() if
+HAVE_BCOPY is defined. If your system has neither bcopy() nor memmove(), make
+sure both macros are undefined; an emulation function will then be used. */
+
+/* By default, the \R escape sequence matches any Unicode line ending
+ character or sequence of characters. If BSR_ANYCRLF is defined (to any
+ value), this is changed so that backslash-R matches only CR, LF, or CRLF.
+ The build-time default can be overridden by the user of PCRE2 at runtime.
+ */
+/* #undef BSR_ANYCRLF */
+
+/* If you are compiling for a system that uses EBCDIC instead of ASCII
+ character codes, define this macro to any value. When EBCDIC is set, PCRE2
+ assumes that all input strings are in EBCDIC. If you do not define this
+ macro, PCRE2 will assume input strings are ASCII or UTF-8/16/32 Unicode. It
+ is not possible to build a version of PCRE2 that supports both EBCDIC and
+ UTF-8/16/32. */
+/* #undef EBCDIC */
+
+/* In an EBCDIC environment, define this macro to any value to arrange for the
+ NL character to be 0x25 instead of the default 0x15. NL plays the role that
+ LF does in an ASCII/Unicode environment. */
+/* #undef EBCDIC_NL25 */
+
+/* Define to 1 if you have the `bcopy' function. */
+/* #undef HAVE_BCOPY */
+
+/* Define to 1 if you have the <bzlib.h> header file. */
+/* #undef HAVE_BZLIB_H */
+
+/* Define to 1 if you have the <dirent.h> header file. */
+/* #undef HAVE_DIRENT_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you have the <editline/readline.h> header file. */
+/* #undef HAVE_EDITLINE_READLINE_H */
+
+/* Define to 1 if you have the <edit/readline/readline.h> header file. */
+/* #undef HAVE_EDIT_READLINE_READLINE_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+/* #undef HAVE_MKOSTEMP */
+
+/* Define if you have POSIX threads libraries and header files. */
+/* #undef HAVE_PTHREAD */
+
+/* Have PTHREAD_PRIO_INHERIT. */
+/* #undef HAVE_PTHREAD_PRIO_INHERIT */
+
+/* Define to 1 if you have the <readline/history.h> header file. */
+/* #undef HAVE_READLINE_HISTORY_H */
+
+/* Define to 1 if you have the <readline/readline.h> header file. */
+/* #undef HAVE_READLINE_READLINE_H */
+
+/* Define to 1 if you have the `secure_getenv' function. */
+/* #undef HAVE_SECURE_GETENV */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/wait.h> header file. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the compiler supports simple visibility declarations. */
+/* #undef HAVE_VISIBILITY */
+
+/* Define to 1 if you have the <windows.h> header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the <zlib.h> header file. */
+/* #undef HAVE_ZLIB_H */
+
+/* This limits the amount of memory that may be used while matching a pattern.
+ It applies to both pcre2_match() and pcre2_dfa_match(). It does not apply
+ to JIT matching. The value is in kibibytes (units of 1024 bytes). */
+#ifndef HEAP_LIMIT
+#define HEAP_LIMIT 2500
+#endif
+
+/* The value of LINK_SIZE determines the number of bytes used to store links
+ as offsets within the compiled regex. The default is 2, which allows for
+ compiled patterns up to 65535 code units long. This covers the vast
+ majority of cases. However, PCRE2 can also be compiled to use 3 or 4 bytes
+ instead. This allows for longer patterns in extreme cases. */
+#ifndef LINK_SIZE
+#define LINK_SIZE 2
+#endif
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+/* This is ignored unless you are using libtool. */
+#ifndef LT_OBJDIR
+#define LT_OBJDIR ".libs/"
+#endif
+
+/* The value of MATCH_LIMIT determines the default number of times the
+ pcre2_match() function can record a backtrack position during a single
+ matching attempt. The value is also used to limit a loop counter in
+ pcre2_dfa_match(). There is a runtime interface for setting a different
+ limit. The limit exists in order to catch runaway regular expressions that
+ take for ever to determine that they do not match. The default is set very
+ large so that it does not accidentally catch legitimate cases. */
+#ifndef MATCH_LIMIT
+#define MATCH_LIMIT 10000000
+#endif
+
+/* The above limit applies to all backtracks, whether or not they are nested.
+ In some environments it is desirable to limit the nesting of backtracking
+ (that is, the depth of tree that is searched) more strictly, in order to
+ restrict the maximum amount of heap memory that is used. The value of
+ MATCH_LIMIT_DEPTH provides this facility. To have any useful effect, it
+ must be less than the value of MATCH_LIMIT. The default is to use the same
+ value as MATCH_LIMIT. There is a runtime method for setting a different
+ limit. In the case of pcre2_dfa_match(), this limit controls the depth of
+ the internal nested function calls that are used for pattern recursions,
+ lookarounds, and atomic groups. */
+#ifndef MATCH_LIMIT_DEPTH
+#define MATCH_LIMIT_DEPTH MATCH_LIMIT
+#endif
+
+/* This limit is parameterized just in case anybody ever wants to change it.
+ Care must be taken if it is increased, because it guards against integer
+ overflow caused by enormously large patterns. */
+#ifndef MAX_NAME_COUNT
+#define MAX_NAME_COUNT 10000
+#endif
+
+/* This limit is parameterized just in case anybody ever wants to change it.
+ Care must be taken if it is increased, because it guards against integer
+ overflow caused by enormously large patterns. */
+#ifndef MAX_NAME_SIZE
+#define MAX_NAME_SIZE 32
+#endif
+
+/* Defining NEVER_BACKSLASH_C locks out the use of \C in all patterns. */
+/* #undef NEVER_BACKSLASH_C */
+
+/* The value of NEWLINE_DEFAULT determines the default newline character
+ sequence. PCRE2 client programs can override this by selecting other values
+ at run time. The valid values are 1 (CR), 2 (LF), 3 (CRLF), 4 (ANY), 5
+ (ANYCRLF), and 6 (NUL). */
+#ifndef NEWLINE_DEFAULT
+#define NEWLINE_DEFAULT 2
+#endif
+
+/* Name of package */
+#define PACKAGE "pcre2"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "PCRE2"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "PCRE2 10.32"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pcre2"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "10.32"
+
+/* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested
+ parentheses (of any kind) in a pattern. This limits the amount of system
+ stack that is used while compiling a pattern. */
+#ifndef PARENS_NEST_LIMIT
+#define PARENS_NEST_LIMIT 250
+#endif
+
+/* The value of PCRE2GREP_BUFSIZE is the starting size of the buffer used by
+ pcre2grep to hold parts of the file it is searching. The buffer will be
+ expanded up to PCRE2GREP_MAX_BUFSIZE if necessary, for files containing
+ very long lines. The actual amount of memory used by pcre2grep is three
+ times this number, because it allows for the buffering of "before" and
+ "after" lines. */
+#ifndef PCRE2GREP_BUFSIZE
+#define PCRE2GREP_BUFSIZE 20480
+#endif
+
+/* The value of PCRE2GREP_MAX_BUFSIZE specifies the maximum size of the buffer
+ used by pcre2grep to hold parts of the file it is searching. The actual
+ amount of memory used by pcre2grep is three times this number, because it
+ allows for the buffering of "before" and "after" lines. */
+#ifndef PCRE2GREP_MAX_BUFSIZE
+#define PCRE2GREP_MAX_BUFSIZE 1048576
+#endif
+
+/* Define to any value to include debugging code. */
+/* #undef PCRE2_DEBUG */
+
+/* If you are compiling for a system other than a Unix-like system or
+ Win32, and it needs some magic to be inserted before the definition
+ of a function that is exported by the library, define this macro to
+ contain the relevant magic. If you do not define this macro, a suitable
+ __declspec value is used for Windows systems; in other environments
+ "extern" is used for a C compiler and "extern C" for a C++ compiler.
+ This macro apears at the start of every exported function that is part
+ of the external API. It does not appear on functions that are "external"
+ in the C sense, but which are internal to the library. */
+/* #undef PCRE2_EXP_DEFN */
+
+/* Define to any value if linking statically (TODO: make nice with Libtool) */
+#define PCRE2_STATIC 1
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Define to any non-zero number to enable support for SELinux compatible
+ executable memory allocator in JIT. Note that this will have no effect
+ unless SUPPORT_JIT is also defined. */
+/* #undef SLJIT_PROT_EXECUTABLE_ALLOCATOR */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to any value to enable support for Just-In-Time compiling. */
+/* #undef SUPPORT_JIT */
+
+/* Define to any value to allow pcre2grep to be linked with libbz2, so that it
+ is able to handle .bz2 files. */
+/* #undef SUPPORT_LIBBZ2 */
+
+/* Define to any value to allow pcre2test to be linked with libedit. */
+/* #undef SUPPORT_LIBEDIT */
+
+/* Define to any value to allow pcre2test to be linked with libreadline. */
+/* #undef SUPPORT_LIBREADLINE */
+
+/* Define to any value to allow pcre2grep to be linked with libz, so that it
+ is able to handle .gz files. */
+/* #undef SUPPORT_LIBZ */
+
+/* Define to any value to enable callout script support in pcre2grep. */
+/* #undef SUPPORT_PCRE2GREP_CALLOUT */
+
+/* Define to any value to enable JIT support in pcre2grep. Note that this will
+ have no effect unless SUPPORT_JIT is also defined. */
+/* #undef SUPPORT_PCRE2GREP_JIT */
+
+/* Define to any value to enable the 16 bit PCRE2 library. */
+/* #undef SUPPORT_PCRE2_16 */
+
+/* Define to any value to enable the 32 bit PCRE2 library. */
+/* #undef SUPPORT_PCRE2_32 */
+
+/* Define to any value to enable the 8 bit PCRE2 library. */
+#define SUPPORT_PCRE2_8 1
+
+/* Define to any value to enable support for Unicode and UTF encoding. This
+ will work even in an EBCDIC environment, but it is incompatible with the
+ EBCDIC macro. That is, PCRE2 can support *either* EBCDIC code *or*
+ ASCII/Unicode, but not both at once. */
+/* #undef SUPPORT_UNICODE */
+
+/* Define to any value for valgrind support to find invalid memory reads. */
+/* #undef SUPPORT_VALGRIND */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+
+/* Version number of package */
+#define VERSION "10.32"
+
+/* Define to 1 if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+ this defined. */
+#define _POSIX_1_SOURCE 1
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#define _POSIX_SOURCE 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+/* #undef int64_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
diff --git a/test/monniaux/pcre2-10.32/pcre2.h b/test/monniaux/pcre2-10.32/pcre2.h
new file mode 100644
index 00000000..3d2feb7a
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2.h
@@ -0,0 +1,974 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* This is the public header file for the PCRE library, second API, to be
+#included by applications that call PCRE2 functions.
+
+ Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef PCRE2_H_IDEMPOTENT_GUARD
+#define PCRE2_H_IDEMPOTENT_GUARD
+
+/* The current PCRE version information. */
+
+#define PCRE2_MAJOR 10
+#define PCRE2_MINOR 32
+#define PCRE2_PRERELEASE
+#define PCRE2_DATE 2018-09-10
+
+/* For the benefit of systems without stdint.h, an alternative is to use
+inttypes.h. The existence of these headers is checked by configure or CMake. */
+
+#define PCRE2_HAVE_STDINT_H 1
+#define PCRE2_HAVE_INTTYPES_H 1
+
+/* When an application links to a PCRE DLL in Windows, the symbols that are
+imported have to be identified as such. When building PCRE2, the appropriate
+export setting is defined in pcre2_internal.h, which includes this file. So we
+don't change existing definitions of PCRE2_EXP_DECL. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC)
+# ifndef PCRE2_EXP_DECL
+# define PCRE2_EXP_DECL extern __declspec(dllimport)
+# endif
+#endif
+
+/* By default, we use the standard "extern" declarations. */
+
+#ifndef PCRE2_EXP_DECL
+# ifdef __cplusplus
+# define PCRE2_EXP_DECL extern "C"
+# else
+# define PCRE2_EXP_DECL extern
+# endif
+#endif
+
+/* When compiling with the MSVC compiler, it is sometimes necessary to include
+a "calling convention" before exported function names. (This is secondhand
+information; I know nothing about MSVC myself). For example, something like
+
+ void __cdecl function(....)
+
+might be needed. In order so make this easy, all the exported functions have
+PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not
+set, we ensure here that it has no effect. */
+
+#ifndef PCRE2_CALL_CONVENTION
+#define PCRE2_CALL_CONVENTION
+#endif
+
+/* Have to include limits.h, stdlib.h and stdint.h (or inttypes.h) to ensure
+that size_t and uint8_t, UCHAR_MAX, etc are defined. If the system has neither
+header, the relevant values must be provided by some other means. */
+
+#include <limits.h>
+#include <stdlib.h>
+
+#if PCRE2_HAVE_STDINT_H
+#include <stdint.h>
+#elif PCRE2_HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* Allow for C++ users compiling this directly. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following option bits can be passed to pcre2_compile(), pcre2_match(),
+or pcre2_dfa_match(). PCRE2_NO_UTF_CHECK affects only the function to which it
+is passed. Put these bits at the most significant end of the options word so
+others can be added next to them */
+
+#define PCRE2_ANCHORED 0x80000000u
+#define PCRE2_NO_UTF_CHECK 0x40000000u
+#define PCRE2_ENDANCHORED 0x20000000u
+
+/* The following option bits can be passed only to pcre2_compile(). However,
+they may affect compilation, JIT compilation, and/or interpretive execution.
+The following tags indicate which:
+
+C alters what is compiled by pcre2_compile()
+J alters what is compiled by pcre2_jit_compile()
+M is inspected during pcre2_match() execution
+D is inspected during pcre2_dfa_match() execution
+*/
+
+#define PCRE2_ALLOW_EMPTY_CLASS 0x00000001u /* C */
+#define PCRE2_ALT_BSUX 0x00000002u /* C */
+#define PCRE2_AUTO_CALLOUT 0x00000004u /* C */
+#define PCRE2_CASELESS 0x00000008u /* C */
+#define PCRE2_DOLLAR_ENDONLY 0x00000010u /* J M D */
+#define PCRE2_DOTALL 0x00000020u /* C */
+#define PCRE2_DUPNAMES 0x00000040u /* C */
+#define PCRE2_EXTENDED 0x00000080u /* C */
+#define PCRE2_FIRSTLINE 0x00000100u /* J M D */
+#define PCRE2_MATCH_UNSET_BACKREF 0x00000200u /* C J M */
+#define PCRE2_MULTILINE 0x00000400u /* C */
+#define PCRE2_NEVER_UCP 0x00000800u /* C */
+#define PCRE2_NEVER_UTF 0x00001000u /* C */
+#define PCRE2_NO_AUTO_CAPTURE 0x00002000u /* C */
+#define PCRE2_NO_AUTO_POSSESS 0x00004000u /* C */
+#define PCRE2_NO_DOTSTAR_ANCHOR 0x00008000u /* C */
+#define PCRE2_NO_START_OPTIMIZE 0x00010000u /* J M D */
+#define PCRE2_UCP 0x00020000u /* C J M D */
+#define PCRE2_UNGREEDY 0x00040000u /* C */
+#define PCRE2_UTF 0x00080000u /* C J M D */
+#define PCRE2_NEVER_BACKSLASH_C 0x00100000u /* C */
+#define PCRE2_ALT_CIRCUMFLEX 0x00200000u /* J M D */
+#define PCRE2_ALT_VERBNAMES 0x00400000u /* C */
+#define PCRE2_USE_OFFSET_LIMIT 0x00800000u /* J M D */
+#define PCRE2_EXTENDED_MORE 0x01000000u /* C */
+#define PCRE2_LITERAL 0x02000000u /* C */
+
+/* An additional compile options word is available in the compile context. */
+
+#define PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES 0x00000001u /* C */
+#define PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL 0x00000002u /* C */
+#define PCRE2_EXTRA_MATCH_WORD 0x00000004u /* C */
+#define PCRE2_EXTRA_MATCH_LINE 0x00000008u /* C */
+
+/* These are for pcre2_jit_compile(). */
+
+#define PCRE2_JIT_COMPLETE 0x00000001u /* For full matching */
+#define PCRE2_JIT_PARTIAL_SOFT 0x00000002u
+#define PCRE2_JIT_PARTIAL_HARD 0x00000004u
+
+/* These are for pcre2_match(), pcre2_dfa_match(), and pcre2_jit_match(). Note
+that PCRE2_ANCHORED and PCRE2_NO_UTF_CHECK can also be passed to these
+functions (though pcre2_jit_match() ignores the latter since it bypasses all
+sanity checks). */
+
+#define PCRE2_NOTBOL 0x00000001u
+#define PCRE2_NOTEOL 0x00000002u
+#define PCRE2_NOTEMPTY 0x00000004u /* ) These two must be kept */
+#define PCRE2_NOTEMPTY_ATSTART 0x00000008u /* ) adjacent to each other. */
+#define PCRE2_PARTIAL_SOFT 0x00000010u
+#define PCRE2_PARTIAL_HARD 0x00000020u
+
+/* These are additional options for pcre2_dfa_match(). */
+
+#define PCRE2_DFA_RESTART 0x00000040u
+#define PCRE2_DFA_SHORTEST 0x00000080u
+
+/* These are additional options for pcre2_substitute(), which passes any others
+through to pcre2_match(). */
+
+#define PCRE2_SUBSTITUTE_GLOBAL 0x00000100u
+#define PCRE2_SUBSTITUTE_EXTENDED 0x00000200u
+#define PCRE2_SUBSTITUTE_UNSET_EMPTY 0x00000400u
+#define PCRE2_SUBSTITUTE_UNKNOWN_UNSET 0x00000800u
+#define PCRE2_SUBSTITUTE_OVERFLOW_LENGTH 0x00001000u
+
+/* A further option for pcre2_match(), not allowed for pcre2_dfa_match(),
+ignored for pcre2_jit_match(). */
+
+#define PCRE2_NO_JIT 0x00002000u
+
+/* Options for pcre2_pattern_convert(). */
+
+#define PCRE2_CONVERT_UTF 0x00000001u
+#define PCRE2_CONVERT_NO_UTF_CHECK 0x00000002u
+#define PCRE2_CONVERT_POSIX_BASIC 0x00000004u
+#define PCRE2_CONVERT_POSIX_EXTENDED 0x00000008u
+#define PCRE2_CONVERT_GLOB 0x00000010u
+#define PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR 0x00000030u
+#define PCRE2_CONVERT_GLOB_NO_STARSTAR 0x00000050u
+
+/* Newline and \R settings, for use in compile contexts. The newline values
+must be kept in step with values set in config.h and both sets must all be
+greater than zero. */
+
+#define PCRE2_NEWLINE_CR 1
+#define PCRE2_NEWLINE_LF 2
+#define PCRE2_NEWLINE_CRLF 3
+#define PCRE2_NEWLINE_ANY 4
+#define PCRE2_NEWLINE_ANYCRLF 5
+#define PCRE2_NEWLINE_NUL 6
+
+#define PCRE2_BSR_UNICODE 1
+#define PCRE2_BSR_ANYCRLF 2
+
+/* Error codes for pcre2_compile(). Some of these are also used by
+pcre2_pattern_convert(). */
+
+#define PCRE2_ERROR_END_BACKSLASH 101
+#define PCRE2_ERROR_END_BACKSLASH_C 102
+#define PCRE2_ERROR_UNKNOWN_ESCAPE 103
+#define PCRE2_ERROR_QUANTIFIER_OUT_OF_ORDER 104
+#define PCRE2_ERROR_QUANTIFIER_TOO_BIG 105
+#define PCRE2_ERROR_MISSING_SQUARE_BRACKET 106
+#define PCRE2_ERROR_ESCAPE_INVALID_IN_CLASS 107
+#define PCRE2_ERROR_CLASS_RANGE_ORDER 108
+#define PCRE2_ERROR_QUANTIFIER_INVALID 109
+#define PCRE2_ERROR_INTERNAL_UNEXPECTED_REPEAT 110
+#define PCRE2_ERROR_INVALID_AFTER_PARENS_QUERY 111
+#define PCRE2_ERROR_POSIX_CLASS_NOT_IN_CLASS 112
+#define PCRE2_ERROR_POSIX_NO_SUPPORT_COLLATING 113
+#define PCRE2_ERROR_MISSING_CLOSING_PARENTHESIS 114
+#define PCRE2_ERROR_BAD_SUBPATTERN_REFERENCE 115
+#define PCRE2_ERROR_NULL_PATTERN 116
+#define PCRE2_ERROR_BAD_OPTIONS 117
+#define PCRE2_ERROR_MISSING_COMMENT_CLOSING 118
+#define PCRE2_ERROR_PARENTHESES_NEST_TOO_DEEP 119
+#define PCRE2_ERROR_PATTERN_TOO_LARGE 120
+#define PCRE2_ERROR_HEAP_FAILED 121
+#define PCRE2_ERROR_UNMATCHED_CLOSING_PARENTHESIS 122
+#define PCRE2_ERROR_INTERNAL_CODE_OVERFLOW 123
+#define PCRE2_ERROR_MISSING_CONDITION_CLOSING 124
+#define PCRE2_ERROR_LOOKBEHIND_NOT_FIXED_LENGTH 125
+#define PCRE2_ERROR_ZERO_RELATIVE_REFERENCE 126
+#define PCRE2_ERROR_TOO_MANY_CONDITION_BRANCHES 127
+#define PCRE2_ERROR_CONDITION_ASSERTION_EXPECTED 128
+#define PCRE2_ERROR_BAD_RELATIVE_REFERENCE 129
+#define PCRE2_ERROR_UNKNOWN_POSIX_CLASS 130
+#define PCRE2_ERROR_INTERNAL_STUDY_ERROR 131
+#define PCRE2_ERROR_UNICODE_NOT_SUPPORTED 132
+#define PCRE2_ERROR_PARENTHESES_STACK_CHECK 133
+#define PCRE2_ERROR_CODE_POINT_TOO_BIG 134
+#define PCRE2_ERROR_LOOKBEHIND_TOO_COMPLICATED 135
+#define PCRE2_ERROR_LOOKBEHIND_INVALID_BACKSLASH_C 136
+#define PCRE2_ERROR_UNSUPPORTED_ESCAPE_SEQUENCE 137
+#define PCRE2_ERROR_CALLOUT_NUMBER_TOO_BIG 138
+#define PCRE2_ERROR_MISSING_CALLOUT_CLOSING 139
+#define PCRE2_ERROR_ESCAPE_INVALID_IN_VERB 140
+#define PCRE2_ERROR_UNRECOGNIZED_AFTER_QUERY_P 141
+#define PCRE2_ERROR_MISSING_NAME_TERMINATOR 142
+#define PCRE2_ERROR_DUPLICATE_SUBPATTERN_NAME 143
+#define PCRE2_ERROR_INVALID_SUBPATTERN_NAME 144
+#define PCRE2_ERROR_UNICODE_PROPERTIES_UNAVAILABLE 145
+#define PCRE2_ERROR_MALFORMED_UNICODE_PROPERTY 146
+#define PCRE2_ERROR_UNKNOWN_UNICODE_PROPERTY 147
+#define PCRE2_ERROR_SUBPATTERN_NAME_TOO_LONG 148
+#define PCRE2_ERROR_TOO_MANY_NAMED_SUBPATTERNS 149
+#define PCRE2_ERROR_CLASS_INVALID_RANGE 150
+#define PCRE2_ERROR_OCTAL_BYTE_TOO_BIG 151
+#define PCRE2_ERROR_INTERNAL_OVERRAN_WORKSPACE 152
+#define PCRE2_ERROR_INTERNAL_MISSING_SUBPATTERN 153
+#define PCRE2_ERROR_DEFINE_TOO_MANY_BRANCHES 154
+#define PCRE2_ERROR_BACKSLASH_O_MISSING_BRACE 155
+#define PCRE2_ERROR_INTERNAL_UNKNOWN_NEWLINE 156
+#define PCRE2_ERROR_BACKSLASH_G_SYNTAX 157
+#define PCRE2_ERROR_PARENS_QUERY_R_MISSING_CLOSING 158
+/* Error 159 is obsolete and should now never occur */
+#define PCRE2_ERROR_VERB_ARGUMENT_NOT_ALLOWED 159
+#define PCRE2_ERROR_VERB_UNKNOWN 160
+#define PCRE2_ERROR_SUBPATTERN_NUMBER_TOO_BIG 161
+#define PCRE2_ERROR_SUBPATTERN_NAME_EXPECTED 162
+#define PCRE2_ERROR_INTERNAL_PARSED_OVERFLOW 163
+#define PCRE2_ERROR_INVALID_OCTAL 164
+#define PCRE2_ERROR_SUBPATTERN_NAMES_MISMATCH 165
+#define PCRE2_ERROR_MARK_MISSING_ARGUMENT 166
+#define PCRE2_ERROR_INVALID_HEXADECIMAL 167
+#define PCRE2_ERROR_BACKSLASH_C_SYNTAX 168
+#define PCRE2_ERROR_BACKSLASH_K_SYNTAX 169
+#define PCRE2_ERROR_INTERNAL_BAD_CODE_LOOKBEHINDS 170
+#define PCRE2_ERROR_BACKSLASH_N_IN_CLASS 171
+#define PCRE2_ERROR_CALLOUT_STRING_TOO_LONG 172
+#define PCRE2_ERROR_UNICODE_DISALLOWED_CODE_POINT 173
+#define PCRE2_ERROR_UTF_IS_DISABLED 174
+#define PCRE2_ERROR_UCP_IS_DISABLED 175
+#define PCRE2_ERROR_VERB_NAME_TOO_LONG 176
+#define PCRE2_ERROR_BACKSLASH_U_CODE_POINT_TOO_BIG 177
+#define PCRE2_ERROR_MISSING_OCTAL_OR_HEX_DIGITS 178
+#define PCRE2_ERROR_VERSION_CONDITION_SYNTAX 179
+#define PCRE2_ERROR_INTERNAL_BAD_CODE_AUTO_POSSESS 180
+#define PCRE2_ERROR_CALLOUT_NO_STRING_DELIMITER 181
+#define PCRE2_ERROR_CALLOUT_BAD_STRING_DELIMITER 182
+#define PCRE2_ERROR_BACKSLASH_C_CALLER_DISABLED 183
+#define PCRE2_ERROR_QUERY_BARJX_NEST_TOO_DEEP 184
+#define PCRE2_ERROR_BACKSLASH_C_LIBRARY_DISABLED 185
+#define PCRE2_ERROR_PATTERN_TOO_COMPLICATED 186
+#define PCRE2_ERROR_LOOKBEHIND_TOO_LONG 187
+#define PCRE2_ERROR_PATTERN_STRING_TOO_LONG 188
+#define PCRE2_ERROR_INTERNAL_BAD_CODE 189
+#define PCRE2_ERROR_INTERNAL_BAD_CODE_IN_SKIP 190
+#define PCRE2_ERROR_NO_SURROGATES_IN_UTF16 191
+#define PCRE2_ERROR_BAD_LITERAL_OPTIONS 192
+#define PCRE2_ERROR_SUPPORTED_ONLY_IN_UNICODE 193
+#define PCRE2_ERROR_INVALID_HYPHEN_IN_OPTIONS 194
+
+
+/* "Expected" matching error codes: no match and partial match. */
+
+#define PCRE2_ERROR_NOMATCH (-1)
+#define PCRE2_ERROR_PARTIAL (-2)
+
+/* Error codes for UTF-8 validity checks */
+
+#define PCRE2_ERROR_UTF8_ERR1 (-3)
+#define PCRE2_ERROR_UTF8_ERR2 (-4)
+#define PCRE2_ERROR_UTF8_ERR3 (-5)
+#define PCRE2_ERROR_UTF8_ERR4 (-6)
+#define PCRE2_ERROR_UTF8_ERR5 (-7)
+#define PCRE2_ERROR_UTF8_ERR6 (-8)
+#define PCRE2_ERROR_UTF8_ERR7 (-9)
+#define PCRE2_ERROR_UTF8_ERR8 (-10)
+#define PCRE2_ERROR_UTF8_ERR9 (-11)
+#define PCRE2_ERROR_UTF8_ERR10 (-12)
+#define PCRE2_ERROR_UTF8_ERR11 (-13)
+#define PCRE2_ERROR_UTF8_ERR12 (-14)
+#define PCRE2_ERROR_UTF8_ERR13 (-15)
+#define PCRE2_ERROR_UTF8_ERR14 (-16)
+#define PCRE2_ERROR_UTF8_ERR15 (-17)
+#define PCRE2_ERROR_UTF8_ERR16 (-18)
+#define PCRE2_ERROR_UTF8_ERR17 (-19)
+#define PCRE2_ERROR_UTF8_ERR18 (-20)
+#define PCRE2_ERROR_UTF8_ERR19 (-21)
+#define PCRE2_ERROR_UTF8_ERR20 (-22)
+#define PCRE2_ERROR_UTF8_ERR21 (-23)
+
+/* Error codes for UTF-16 validity checks */
+
+#define PCRE2_ERROR_UTF16_ERR1 (-24)
+#define PCRE2_ERROR_UTF16_ERR2 (-25)
+#define PCRE2_ERROR_UTF16_ERR3 (-26)
+
+/* Error codes for UTF-32 validity checks */
+
+#define PCRE2_ERROR_UTF32_ERR1 (-27)
+#define PCRE2_ERROR_UTF32_ERR2 (-28)
+
+/* Miscellaneous error codes for pcre2[_dfa]_match(), substring extraction
+functions, context functions, and serializing functions. They are in numerical
+order. Originally they were in alphabetical order too, but now that PCRE2 is
+released, the numbers must not be changed. */
+
+#define PCRE2_ERROR_BADDATA (-29)
+#define PCRE2_ERROR_MIXEDTABLES (-30) /* Name was changed */
+#define PCRE2_ERROR_BADMAGIC (-31)
+#define PCRE2_ERROR_BADMODE (-32)
+#define PCRE2_ERROR_BADOFFSET (-33)
+#define PCRE2_ERROR_BADOPTION (-34)
+#define PCRE2_ERROR_BADREPLACEMENT (-35)
+#define PCRE2_ERROR_BADUTFOFFSET (-36)
+#define PCRE2_ERROR_CALLOUT (-37) /* Never used by PCRE2 itself */
+#define PCRE2_ERROR_DFA_BADRESTART (-38)
+#define PCRE2_ERROR_DFA_RECURSE (-39)
+#define PCRE2_ERROR_DFA_UCOND (-40)
+#define PCRE2_ERROR_DFA_UFUNC (-41)
+#define PCRE2_ERROR_DFA_UITEM (-42)
+#define PCRE2_ERROR_DFA_WSSIZE (-43)
+#define PCRE2_ERROR_INTERNAL (-44)
+#define PCRE2_ERROR_JIT_BADOPTION (-45)
+#define PCRE2_ERROR_JIT_STACKLIMIT (-46)
+#define PCRE2_ERROR_MATCHLIMIT (-47)
+#define PCRE2_ERROR_NOMEMORY (-48)
+#define PCRE2_ERROR_NOSUBSTRING (-49)
+#define PCRE2_ERROR_NOUNIQUESUBSTRING (-50)
+#define PCRE2_ERROR_NULL (-51)
+#define PCRE2_ERROR_RECURSELOOP (-52)
+#define PCRE2_ERROR_DEPTHLIMIT (-53)
+#define PCRE2_ERROR_RECURSIONLIMIT (-53) /* Obsolete synonym */
+#define PCRE2_ERROR_UNAVAILABLE (-54)
+#define PCRE2_ERROR_UNSET (-55)
+#define PCRE2_ERROR_BADOFFSETLIMIT (-56)
+#define PCRE2_ERROR_BADREPESCAPE (-57)
+#define PCRE2_ERROR_REPMISSINGBRACE (-58)
+#define PCRE2_ERROR_BADSUBSTITUTION (-59)
+#define PCRE2_ERROR_BADSUBSPATTERN (-60)
+#define PCRE2_ERROR_TOOMANYREPLACE (-61)
+#define PCRE2_ERROR_BADSERIALIZEDDATA (-62)
+#define PCRE2_ERROR_HEAPLIMIT (-63)
+#define PCRE2_ERROR_CONVERT_SYNTAX (-64)
+#define PCRE2_ERROR_INTERNAL_DUPMATCH (-65)
+
+
+/* Request types for pcre2_pattern_info() */
+
+#define PCRE2_INFO_ALLOPTIONS 0
+#define PCRE2_INFO_ARGOPTIONS 1
+#define PCRE2_INFO_BACKREFMAX 2
+#define PCRE2_INFO_BSR 3
+#define PCRE2_INFO_CAPTURECOUNT 4
+#define PCRE2_INFO_FIRSTCODEUNIT 5
+#define PCRE2_INFO_FIRSTCODETYPE 6
+#define PCRE2_INFO_FIRSTBITMAP 7
+#define PCRE2_INFO_HASCRORLF 8
+#define PCRE2_INFO_JCHANGED 9
+#define PCRE2_INFO_JITSIZE 10
+#define PCRE2_INFO_LASTCODEUNIT 11
+#define PCRE2_INFO_LASTCODETYPE 12
+#define PCRE2_INFO_MATCHEMPTY 13
+#define PCRE2_INFO_MATCHLIMIT 14
+#define PCRE2_INFO_MAXLOOKBEHIND 15
+#define PCRE2_INFO_MINLENGTH 16
+#define PCRE2_INFO_NAMECOUNT 17
+#define PCRE2_INFO_NAMEENTRYSIZE 18
+#define PCRE2_INFO_NAMETABLE 19
+#define PCRE2_INFO_NEWLINE 20
+#define PCRE2_INFO_DEPTHLIMIT 21
+#define PCRE2_INFO_RECURSIONLIMIT 21 /* Obsolete synonym */
+#define PCRE2_INFO_SIZE 22
+#define PCRE2_INFO_HASBACKSLASHC 23
+#define PCRE2_INFO_FRAMESIZE 24
+#define PCRE2_INFO_HEAPLIMIT 25
+#define PCRE2_INFO_EXTRAOPTIONS 26
+
+/* Request types for pcre2_config(). */
+
+#define PCRE2_CONFIG_BSR 0
+#define PCRE2_CONFIG_JIT 1
+#define PCRE2_CONFIG_JITTARGET 2
+#define PCRE2_CONFIG_LINKSIZE 3
+#define PCRE2_CONFIG_MATCHLIMIT 4
+#define PCRE2_CONFIG_NEWLINE 5
+#define PCRE2_CONFIG_PARENSLIMIT 6
+#define PCRE2_CONFIG_DEPTHLIMIT 7
+#define PCRE2_CONFIG_RECURSIONLIMIT 7 /* Obsolete synonym */
+#define PCRE2_CONFIG_STACKRECURSE 8 /* Obsolete */
+#define PCRE2_CONFIG_UNICODE 9
+#define PCRE2_CONFIG_UNICODE_VERSION 10
+#define PCRE2_CONFIG_VERSION 11
+#define PCRE2_CONFIG_HEAPLIMIT 12
+#define PCRE2_CONFIG_NEVER_BACKSLASH_C 13
+#define PCRE2_CONFIG_COMPILED_WIDTHS 14
+
+
+/* Types for code units in patterns and subject strings. */
+
+typedef uint8_t PCRE2_UCHAR8;
+typedef uint16_t PCRE2_UCHAR16;
+typedef uint32_t PCRE2_UCHAR32;
+
+typedef const PCRE2_UCHAR8 *PCRE2_SPTR8;
+typedef const PCRE2_UCHAR16 *PCRE2_SPTR16;
+typedef const PCRE2_UCHAR32 *PCRE2_SPTR32;
+
+/* The PCRE2_SIZE type is used for all string lengths and offsets in PCRE2,
+including pattern offsets for errors and subject offsets after a match. We
+define special values to indicate zero-terminated strings and unset offsets in
+the offset vector (ovector). */
+
+#define PCRE2_SIZE size_t
+#define PCRE2_SIZE_MAX SIZE_MAX
+#define PCRE2_ZERO_TERMINATED (~(PCRE2_SIZE)0)
+#define PCRE2_UNSET (~(PCRE2_SIZE)0)
+
+/* Generic types for opaque structures and JIT callback functions. These
+declarations are defined in a macro that is expanded for each width later. */
+
+#define PCRE2_TYPES_LIST \
+struct pcre2_real_general_context; \
+typedef struct pcre2_real_general_context pcre2_general_context; \
+\
+struct pcre2_real_compile_context; \
+typedef struct pcre2_real_compile_context pcre2_compile_context; \
+\
+struct pcre2_real_match_context; \
+typedef struct pcre2_real_match_context pcre2_match_context; \
+\
+struct pcre2_real_convert_context; \
+typedef struct pcre2_real_convert_context pcre2_convert_context; \
+\
+struct pcre2_real_code; \
+typedef struct pcre2_real_code pcre2_code; \
+\
+struct pcre2_real_match_data; \
+typedef struct pcre2_real_match_data pcre2_match_data; \
+\
+struct pcre2_real_jit_stack; \
+typedef struct pcre2_real_jit_stack pcre2_jit_stack; \
+\
+typedef pcre2_jit_stack *(*pcre2_jit_callback)(void *);
+
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. Define the generic version in a macro; the width-specific
+versions are generated from this macro below. */
+
+/* Flags for the callout_flags field. These are cleared after a callout. */
+
+#define PCRE2_CALLOUT_STARTMATCH 0x00000001u /* Set for each bumpalong */
+#define PCRE2_CALLOUT_BACKTRACK 0x00000002u /* Set after a backtrack */
+
+#define PCRE2_STRUCTURE_LIST \
+typedef struct pcre2_callout_block { \
+ uint32_t version; /* Identifies version of block */ \
+ /* ------------------------ Version 0 ------------------------------- */ \
+ uint32_t callout_number; /* Number compiled into pattern */ \
+ uint32_t capture_top; /* Max current capture */ \
+ uint32_t capture_last; /* Most recently closed capture */ \
+ PCRE2_SIZE *offset_vector; /* The offset vector */ \
+ PCRE2_SPTR mark; /* Pointer to current mark or NULL */ \
+ PCRE2_SPTR subject; /* The subject being matched */ \
+ PCRE2_SIZE subject_length; /* The length of the subject */ \
+ PCRE2_SIZE start_match; /* Offset to start of this match attempt */ \
+ PCRE2_SIZE current_position; /* Where we currently are in the subject */ \
+ PCRE2_SIZE pattern_position; /* Offset to next item in the pattern */ \
+ PCRE2_SIZE next_item_length; /* Length of next item in the pattern */ \
+ /* ------------------- Added for Version 1 -------------------------- */ \
+ PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \
+ PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \
+ PCRE2_SPTR callout_string; /* String compiled into pattern */ \
+ /* ------------------- Added for Version 2 -------------------------- */ \
+ uint32_t callout_flags; /* See above for list */ \
+ /* ------------------------------------------------------------------ */ \
+} pcre2_callout_block; \
+\
+typedef struct pcre2_callout_enumerate_block { \
+ uint32_t version; /* Identifies version of block */ \
+ /* ------------------------ Version 0 ------------------------------- */ \
+ PCRE2_SIZE pattern_position; /* Offset to next item in the pattern */ \
+ PCRE2_SIZE next_item_length; /* Length of next item in the pattern */ \
+ uint32_t callout_number; /* Number compiled into pattern */ \
+ PCRE2_SIZE callout_string_offset; /* Offset to string within pattern */ \
+ PCRE2_SIZE callout_string_length; /* Length of string compiled into pattern */ \
+ PCRE2_SPTR callout_string; /* String compiled into pattern */ \
+ /* ------------------------------------------------------------------ */ \
+} pcre2_callout_enumerate_block;
+
+
+/* List the generic forms of all other functions in macros, which will be
+expanded for each width below. Start with functions that give general
+information. */
+
+#define PCRE2_GENERAL_INFO_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION pcre2_config(uint32_t, void *);
+
+
+/* Functions for manipulating contexts. */
+
+#define PCRE2_GENERAL_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \
+ *pcre2_general_context_copy(pcre2_general_context *); \
+PCRE2_EXP_DECL pcre2_general_context PCRE2_CALL_CONVENTION \
+ *pcre2_general_context_create(void *(*)(PCRE2_SIZE, void *), \
+ void (*)(void *, void *), void *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_general_context_free(pcre2_general_context *);
+
+#define PCRE2_COMPILE_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_compile_context PCRE2_CALL_CONVENTION \
+ *pcre2_compile_context_copy(pcre2_compile_context *); \
+PCRE2_EXP_DECL pcre2_compile_context PCRE2_CALL_CONVENTION \
+ *pcre2_compile_context_create(pcre2_general_context *);\
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_compile_context_free(pcre2_compile_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_bsr(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_character_tables(pcre2_compile_context *, const unsigned char *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_compile_extra_options(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_max_pattern_length(pcre2_compile_context *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_newline(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_parens_nest_limit(pcre2_compile_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_compile_recursion_guard(pcre2_compile_context *, \
+ int (*)(uint32_t, void *), void *);
+
+#define PCRE2_MATCH_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_match_context PCRE2_CALL_CONVENTION \
+ *pcre2_match_context_copy(pcre2_match_context *); \
+PCRE2_EXP_DECL pcre2_match_context PCRE2_CALL_CONVENTION \
+ *pcre2_match_context_create(pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_match_context_free(pcre2_match_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_callout(pcre2_match_context *, \
+ int (*)(pcre2_callout_block *, void *), void *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_depth_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_heap_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_match_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_offset_limit(pcre2_match_context *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_recursion_limit(pcre2_match_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_recursion_memory_management(pcre2_match_context *, \
+ void *(*)(PCRE2_SIZE, void *), void (*)(void *, void *), void *);
+
+#define PCRE2_CONVERT_CONTEXT_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_convert_context PCRE2_CALL_CONVENTION \
+ *pcre2_convert_context_copy(pcre2_convert_context *); \
+PCRE2_EXP_DECL pcre2_convert_context PCRE2_CALL_CONVENTION \
+ *pcre2_convert_context_create(pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_convert_context_free(pcre2_convert_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_glob_escape(pcre2_convert_context *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_set_glob_separator(pcre2_convert_context *, uint32_t);
+
+
+/* Functions concerned with compiling a pattern to PCRE internal code. */
+
+#define PCRE2_COMPILE_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \
+ *pcre2_compile(PCRE2_SPTR, PCRE2_SIZE, uint32_t, int *, PCRE2_SIZE *, \
+ pcre2_compile_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_code_free(pcre2_code *); \
+PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \
+ *pcre2_code_copy(const pcre2_code *); \
+PCRE2_EXP_DECL pcre2_code PCRE2_CALL_CONVENTION \
+ *pcre2_code_copy_with_tables(const pcre2_code *);
+
+
+/* Functions that give information about a compiled pattern. */
+
+#define PCRE2_PATTERN_INFO_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_pattern_info(const pcre2_code *, uint32_t, void *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_callout_enumerate(const pcre2_code *, \
+ int (*)(pcre2_callout_enumerate_block *, void *), void *);
+
+
+/* Functions for running a match and inspecting the result. */
+
+#define PCRE2_MATCH_FUNCTIONS \
+PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \
+ *pcre2_match_data_create(uint32_t, pcre2_general_context *); \
+PCRE2_EXP_DECL pcre2_match_data PCRE2_CALL_CONVENTION \
+ *pcre2_match_data_create_from_pattern(const pcre2_code *, \
+ pcre2_general_context *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_dfa_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+ uint32_t, pcre2_match_data *, pcre2_match_context *, int *, PCRE2_SIZE); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+ uint32_t, pcre2_match_data *, pcre2_match_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_match_data_free(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SPTR PCRE2_CALL_CONVENTION \
+ pcre2_get_mark(pcre2_match_data *); \
+PCRE2_EXP_DECL uint32_t PCRE2_CALL_CONVENTION \
+ pcre2_get_ovector_count(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+ *pcre2_get_ovector_pointer(pcre2_match_data *); \
+PCRE2_EXP_DECL PCRE2_SIZE PCRE2_CALL_CONVENTION \
+ pcre2_get_startchar(pcre2_match_data *);
+
+
+/* Convenience functions for handling matched substrings. */
+
+#define PCRE2_SUBSTRING_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_copy_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR *, \
+ PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_copy_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR *, \
+ PCRE2_SIZE *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_substring_free(PCRE2_UCHAR *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_get_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_UCHAR **, \
+ PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_get_bynumber(pcre2_match_data *, uint32_t, PCRE2_UCHAR **, \
+ PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_length_byname(pcre2_match_data *, PCRE2_SPTR, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_length_bynumber(pcre2_match_data *, uint32_t, PCRE2_SIZE *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_nametable_scan(const pcre2_code *, PCRE2_SPTR, PCRE2_SPTR *, \
+ PCRE2_SPTR *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_number_from_name(const pcre2_code *, PCRE2_SPTR); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_substring_list_free(PCRE2_SPTR *); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substring_list_get(pcre2_match_data *, PCRE2_UCHAR ***, PCRE2_SIZE **);
+
+/* Functions for serializing / deserializing compiled patterns. */
+
+#define PCRE2_SERIALIZE_FUNCTIONS \
+PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \
+ pcre2_serialize_encode(const pcre2_code **, int32_t, uint8_t **, \
+ PCRE2_SIZE *, pcre2_general_context *); \
+PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \
+ pcre2_serialize_decode(pcre2_code **, int32_t, const uint8_t *, \
+ pcre2_general_context *); \
+PCRE2_EXP_DECL int32_t PCRE2_CALL_CONVENTION \
+ pcre2_serialize_get_number_of_codes(const uint8_t *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_serialize_free(uint8_t *);
+
+
+/* Convenience function for match + substitute. */
+
+#define PCRE2_SUBSTITUTE_FUNCTION \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_substitute(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+ uint32_t, pcre2_match_data *, pcre2_match_context *, PCRE2_SPTR, \
+ PCRE2_SIZE, PCRE2_UCHAR *, PCRE2_SIZE *);
+
+
+/* Functions for converting pattern source strings. */
+
+#define PCRE2_CONVERT_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_pattern_convert(PCRE2_SPTR, PCRE2_SIZE, uint32_t, PCRE2_UCHAR **, \
+ PCRE2_SIZE *, pcre2_convert_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_converted_pattern_free(PCRE2_UCHAR *);
+
+
+/* Functions for JIT processing */
+
+#define PCRE2_JIT_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_jit_compile(pcre2_code *, uint32_t); \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_jit_match(const pcre2_code *, PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE, \
+ uint32_t, pcre2_match_data *, pcre2_match_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_jit_free_unused_memory(pcre2_general_context *); \
+PCRE2_EXP_DECL pcre2_jit_stack PCRE2_CALL_CONVENTION \
+ *pcre2_jit_stack_create(PCRE2_SIZE, PCRE2_SIZE, pcre2_general_context *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_jit_stack_assign(pcre2_match_context *, pcre2_jit_callback, void *); \
+PCRE2_EXP_DECL void PCRE2_CALL_CONVENTION \
+ pcre2_jit_stack_free(pcre2_jit_stack *);
+
+
+/* Other miscellaneous functions. */
+
+#define PCRE2_OTHER_FUNCTIONS \
+PCRE2_EXP_DECL int PCRE2_CALL_CONVENTION \
+ pcre2_get_error_message(int, PCRE2_UCHAR *, PCRE2_SIZE); \
+PCRE2_EXP_DECL const uint8_t PCRE2_CALL_CONVENTION \
+ *pcre2_maketables(pcre2_general_context *); \
+
+
+/* Define macros that generate width-specific names from generic versions. The
+three-level macro scheme is necessary to get the macros expanded when we want
+them to be. First we get the width from PCRE2_LOCAL_WIDTH, which is used for
+generating three versions of everything below. After that, PCRE2_SUFFIX will be
+re-defined to use PCRE2_CODE_UNIT_WIDTH, for use when macros such as
+pcre2_compile are called by application code. */
+
+#define PCRE2_JOIN(a,b) a ## b
+#define PCRE2_GLUE(a,b) PCRE2_JOIN(a,b)
+#define PCRE2_SUFFIX(a) PCRE2_GLUE(a,PCRE2_LOCAL_WIDTH)
+
+
+/* Data types */
+
+#define PCRE2_UCHAR PCRE2_SUFFIX(PCRE2_UCHAR)
+#define PCRE2_SPTR PCRE2_SUFFIX(PCRE2_SPTR)
+
+#define pcre2_code PCRE2_SUFFIX(pcre2_code_)
+#define pcre2_jit_callback PCRE2_SUFFIX(pcre2_jit_callback_)
+#define pcre2_jit_stack PCRE2_SUFFIX(pcre2_jit_stack_)
+
+#define pcre2_real_code PCRE2_SUFFIX(pcre2_real_code_)
+#define pcre2_real_general_context PCRE2_SUFFIX(pcre2_real_general_context_)
+#define pcre2_real_compile_context PCRE2_SUFFIX(pcre2_real_compile_context_)
+#define pcre2_real_convert_context PCRE2_SUFFIX(pcre2_real_convert_context_)
+#define pcre2_real_match_context PCRE2_SUFFIX(pcre2_real_match_context_)
+#define pcre2_real_jit_stack PCRE2_SUFFIX(pcre2_real_jit_stack_)
+#define pcre2_real_match_data PCRE2_SUFFIX(pcre2_real_match_data_)
+
+
+/* Data blocks */
+
+#define pcre2_callout_block PCRE2_SUFFIX(pcre2_callout_block_)
+#define pcre2_callout_enumerate_block PCRE2_SUFFIX(pcre2_callout_enumerate_block_)
+#define pcre2_general_context PCRE2_SUFFIX(pcre2_general_context_)
+#define pcre2_compile_context PCRE2_SUFFIX(pcre2_compile_context_)
+#define pcre2_convert_context PCRE2_SUFFIX(pcre2_convert_context_)
+#define pcre2_match_context PCRE2_SUFFIX(pcre2_match_context_)
+#define pcre2_match_data PCRE2_SUFFIX(pcre2_match_data_)
+
+
+/* Functions: the complete list in alphabetical order */
+
+#define pcre2_callout_enumerate PCRE2_SUFFIX(pcre2_callout_enumerate_)
+#define pcre2_code_copy PCRE2_SUFFIX(pcre2_code_copy_)
+#define pcre2_code_copy_with_tables PCRE2_SUFFIX(pcre2_code_copy_with_tables_)
+#define pcre2_code_free PCRE2_SUFFIX(pcre2_code_free_)
+#define pcre2_compile PCRE2_SUFFIX(pcre2_compile_)
+#define pcre2_compile_context_copy PCRE2_SUFFIX(pcre2_compile_context_copy_)
+#define pcre2_compile_context_create PCRE2_SUFFIX(pcre2_compile_context_create_)
+#define pcre2_compile_context_free PCRE2_SUFFIX(pcre2_compile_context_free_)
+#define pcre2_config PCRE2_SUFFIX(pcre2_config_)
+#define pcre2_convert_context_copy PCRE2_SUFFIX(pcre2_convert_context_copy_)
+#define pcre2_convert_context_create PCRE2_SUFFIX(pcre2_convert_context_create_)
+#define pcre2_convert_context_free PCRE2_SUFFIX(pcre2_convert_context_free_)
+#define pcre2_converted_pattern_free PCRE2_SUFFIX(pcre2_converted_pattern_free_)
+#define pcre2_dfa_match PCRE2_SUFFIX(pcre2_dfa_match_)
+#define pcre2_general_context_copy PCRE2_SUFFIX(pcre2_general_context_copy_)
+#define pcre2_general_context_create PCRE2_SUFFIX(pcre2_general_context_create_)
+#define pcre2_general_context_free PCRE2_SUFFIX(pcre2_general_context_free_)
+#define pcre2_get_error_message PCRE2_SUFFIX(pcre2_get_error_message_)
+#define pcre2_get_mark PCRE2_SUFFIX(pcre2_get_mark_)
+#define pcre2_get_ovector_pointer PCRE2_SUFFIX(pcre2_get_ovector_pointer_)
+#define pcre2_get_ovector_count PCRE2_SUFFIX(pcre2_get_ovector_count_)
+#define pcre2_get_startchar PCRE2_SUFFIX(pcre2_get_startchar_)
+#define pcre2_jit_compile PCRE2_SUFFIX(pcre2_jit_compile_)
+#define pcre2_jit_match PCRE2_SUFFIX(pcre2_jit_match_)
+#define pcre2_jit_free_unused_memory PCRE2_SUFFIX(pcre2_jit_free_unused_memory_)
+#define pcre2_jit_stack_assign PCRE2_SUFFIX(pcre2_jit_stack_assign_)
+#define pcre2_jit_stack_create PCRE2_SUFFIX(pcre2_jit_stack_create_)
+#define pcre2_jit_stack_free PCRE2_SUFFIX(pcre2_jit_stack_free_)
+#define pcre2_maketables PCRE2_SUFFIX(pcre2_maketables_)
+#define pcre2_match PCRE2_SUFFIX(pcre2_match_)
+#define pcre2_match_context_copy PCRE2_SUFFIX(pcre2_match_context_copy_)
+#define pcre2_match_context_create PCRE2_SUFFIX(pcre2_match_context_create_)
+#define pcre2_match_context_free PCRE2_SUFFIX(pcre2_match_context_free_)
+#define pcre2_match_data_create PCRE2_SUFFIX(pcre2_match_data_create_)
+#define pcre2_match_data_create_from_pattern PCRE2_SUFFIX(pcre2_match_data_create_from_pattern_)
+#define pcre2_match_data_free PCRE2_SUFFIX(pcre2_match_data_free_)
+#define pcre2_pattern_convert PCRE2_SUFFIX(pcre2_pattern_convert_)
+#define pcre2_pattern_info PCRE2_SUFFIX(pcre2_pattern_info_)
+#define pcre2_serialize_decode PCRE2_SUFFIX(pcre2_serialize_decode_)
+#define pcre2_serialize_encode PCRE2_SUFFIX(pcre2_serialize_encode_)
+#define pcre2_serialize_free PCRE2_SUFFIX(pcre2_serialize_free_)
+#define pcre2_serialize_get_number_of_codes PCRE2_SUFFIX(pcre2_serialize_get_number_of_codes_)
+#define pcre2_set_bsr PCRE2_SUFFIX(pcre2_set_bsr_)
+#define pcre2_set_callout PCRE2_SUFFIX(pcre2_set_callout_)
+#define pcre2_set_character_tables PCRE2_SUFFIX(pcre2_set_character_tables_)
+#define pcre2_set_compile_extra_options PCRE2_SUFFIX(pcre2_set_compile_extra_options_)
+#define pcre2_set_compile_recursion_guard PCRE2_SUFFIX(pcre2_set_compile_recursion_guard_)
+#define pcre2_set_depth_limit PCRE2_SUFFIX(pcre2_set_depth_limit_)
+#define pcre2_set_glob_escape PCRE2_SUFFIX(pcre2_set_glob_escape_)
+#define pcre2_set_glob_separator PCRE2_SUFFIX(pcre2_set_glob_separator_)
+#define pcre2_set_heap_limit PCRE2_SUFFIX(pcre2_set_heap_limit_)
+#define pcre2_set_match_limit PCRE2_SUFFIX(pcre2_set_match_limit_)
+#define pcre2_set_max_pattern_length PCRE2_SUFFIX(pcre2_set_max_pattern_length_)
+#define pcre2_set_newline PCRE2_SUFFIX(pcre2_set_newline_)
+#define pcre2_set_parens_nest_limit PCRE2_SUFFIX(pcre2_set_parens_nest_limit_)
+#define pcre2_set_offset_limit PCRE2_SUFFIX(pcre2_set_offset_limit_)
+#define pcre2_substitute PCRE2_SUFFIX(pcre2_substitute_)
+#define pcre2_substring_copy_byname PCRE2_SUFFIX(pcre2_substring_copy_byname_)
+#define pcre2_substring_copy_bynumber PCRE2_SUFFIX(pcre2_substring_copy_bynumber_)
+#define pcre2_substring_free PCRE2_SUFFIX(pcre2_substring_free_)
+#define pcre2_substring_get_byname PCRE2_SUFFIX(pcre2_substring_get_byname_)
+#define pcre2_substring_get_bynumber PCRE2_SUFFIX(pcre2_substring_get_bynumber_)
+#define pcre2_substring_length_byname PCRE2_SUFFIX(pcre2_substring_length_byname_)
+#define pcre2_substring_length_bynumber PCRE2_SUFFIX(pcre2_substring_length_bynumber_)
+#define pcre2_substring_list_get PCRE2_SUFFIX(pcre2_substring_list_get_)
+#define pcre2_substring_list_free PCRE2_SUFFIX(pcre2_substring_list_free_)
+#define pcre2_substring_nametable_scan PCRE2_SUFFIX(pcre2_substring_nametable_scan_)
+#define pcre2_substring_number_from_name PCRE2_SUFFIX(pcre2_substring_number_from_name_)
+
+/* Keep this old function name for backwards compatibility */
+#define pcre2_set_recursion_limit PCRE2_SUFFIX(pcre2_set_recursion_limit_)
+
+/* Keep this obsolete function for backwards compatibility: it is now a noop. */
+#define pcre2_set_recursion_memory_management PCRE2_SUFFIX(pcre2_set_recursion_memory_management_)
+
+/* Now generate all three sets of width-specific structures and function
+prototypes. */
+
+#define PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS \
+PCRE2_TYPES_LIST \
+PCRE2_STRUCTURE_LIST \
+PCRE2_GENERAL_INFO_FUNCTIONS \
+PCRE2_GENERAL_CONTEXT_FUNCTIONS \
+PCRE2_COMPILE_CONTEXT_FUNCTIONS \
+PCRE2_CONVERT_CONTEXT_FUNCTIONS \
+PCRE2_CONVERT_FUNCTIONS \
+PCRE2_MATCH_CONTEXT_FUNCTIONS \
+PCRE2_COMPILE_FUNCTIONS \
+PCRE2_PATTERN_INFO_FUNCTIONS \
+PCRE2_MATCH_FUNCTIONS \
+PCRE2_SUBSTRING_FUNCTIONS \
+PCRE2_SERIALIZE_FUNCTIONS \
+PCRE2_SUBSTITUTE_FUNCTION \
+PCRE2_JIT_FUNCTIONS \
+PCRE2_OTHER_FUNCTIONS
+
+#define PCRE2_LOCAL_WIDTH 8
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+#define PCRE2_LOCAL_WIDTH 16
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+#define PCRE2_LOCAL_WIDTH 32
+PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+#undef PCRE2_LOCAL_WIDTH
+
+/* Undefine the list macros; they are no longer needed. */
+
+#undef PCRE2_TYPES_LIST
+#undef PCRE2_STRUCTURE_LIST
+#undef PCRE2_GENERAL_INFO_FUNCTIONS
+#undef PCRE2_GENERAL_CONTEXT_FUNCTIONS
+#undef PCRE2_COMPILE_CONTEXT_FUNCTIONS
+#undef PCRE2_CONVERT_CONTEXT_FUNCTIONS
+#undef PCRE2_MATCH_CONTEXT_FUNCTIONS
+#undef PCRE2_COMPILE_FUNCTIONS
+#undef PCRE2_PATTERN_INFO_FUNCTIONS
+#undef PCRE2_MATCH_FUNCTIONS
+#undef PCRE2_SUBSTRING_FUNCTIONS
+#undef PCRE2_SERIALIZE_FUNCTIONS
+#undef PCRE2_SUBSTITUTE_FUNCTION
+#undef PCRE2_JIT_FUNCTIONS
+#undef PCRE2_OTHER_FUNCTIONS
+#undef PCRE2_TYPES_STRUCTURES_AND_FUNCTIONS
+
+/* PCRE2_CODE_UNIT_WIDTH must be defined. If it is 8, 16, or 32, redefine
+PCRE2_SUFFIX to use it. If it is 0, undefine the other macros and make
+PCRE2_SUFFIX a no-op. Otherwise, generate an error. */
+
+#undef PCRE2_SUFFIX
+#ifndef PCRE2_CODE_UNIT_WIDTH
+#error PCRE2_CODE_UNIT_WIDTH must be defined before including pcre2.h.
+#error Use 8, 16, or 32; or 0 for a multi-width application.
+#else /* PCRE2_CODE_UNIT_WIDTH is defined */
+#if PCRE2_CODE_UNIT_WIDTH == 8 || \
+ PCRE2_CODE_UNIT_WIDTH == 16 || \
+ PCRE2_CODE_UNIT_WIDTH == 32
+#define PCRE2_SUFFIX(a) PCRE2_GLUE(a, PCRE2_CODE_UNIT_WIDTH)
+#elif PCRE2_CODE_UNIT_WIDTH == 0
+#undef PCRE2_JOIN
+#undef PCRE2_GLUE
+#define PCRE2_SUFFIX(a) a
+#else
+#error PCRE2_CODE_UNIT_WIDTH must be 0, 8, 16, or 32.
+#endif
+#endif /* PCRE2_CODE_UNIT_WIDTH is defined */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* PCRE2_H_IDEMPOTENT_GUARD */
+
+/* End of pcre2.h */
diff --git a/test/monniaux/pcre2-10.32/pcre2_auto_possess.c b/test/monniaux/pcre2-10.32/pcre2_auto_possess.c
new file mode 100644
index 00000000..2ce152e9
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_auto_possess.c
@@ -0,0 +1,1322 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions that scan a compiled pattern and change
+repeats into possessive repeats where possible. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Tables for auto-possessification *
+*************************************************/
+
+/* This table is used to check whether auto-possessification is possible
+between adjacent character-type opcodes. The left-hand (repeated) opcode is
+used to select the row, and the right-hand opcode is use to select the column.
+A value of 1 means that auto-possessification is OK. For example, the second
+value in the first row means that \D+\d can be turned into \D++\d.
+
+The Unicode property types (\P and \p) have to be present to fill out the table
+because of what their opcode values are, but the table values should always be
+zero because property types are handled separately in the code. The last four
+columns apply to items that cannot be repeated, so there is no need to have
+rows for them. Note that OP_DIGIT etc. are generated only when PCRE_UCP is
+*not* set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+
+#define APTROWS (LAST_AUTOTAB_LEFT_OP - FIRST_AUTOTAB_OP + 1)
+#define APTCOLS (LAST_AUTOTAB_RIGHT_OP - FIRST_AUTOTAB_OP + 1)
+
+static const uint8_t autoposstab[APTROWS][APTCOLS] = {
+/* \D \d \S \s \W \w . .+ \C \P \p \R \H \h \V \v \X \Z \z $ $M */
+ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \D */
+ { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \d */
+ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \S */
+ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \s */
+ { 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \W */
+ { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 }, /* \w */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* . */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* .+ */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, /* \C */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \P */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* \p */
+ { 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \R */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, /* \H */
+ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \h */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, /* \V */
+ { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, /* \v */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 } /* \X */
+};
+
+#ifdef SUPPORT_UNICODE
+/* This table is used to check whether auto-possessification is possible
+between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP). The
+left-hand (repeated) opcode is used to select the row, and the right-hand
+opcode is used to select the column. The values are as follows:
+
+ 0 Always return FALSE (never auto-possessify)
+ 1 Character groups are distinct (possessify if both are OP_PROP)
+ 2 Check character categories in the same group (general or particular)
+ 3 TRUE if the two opcodes are not the same (PROP vs NOTPROP)
+
+ 4 Check left general category vs right particular category
+ 5 Check right general category vs left particular category
+
+ 6 Left alphanum vs right general category
+ 7 Left space vs right general category
+ 8 Left word vs right general category
+
+ 9 Right alphanum vs left general category
+ 10 Right space vs left general category
+ 11 Right word vs left general category
+
+ 12 Left alphanum vs right particular category
+ 13 Left space vs right particular category
+ 14 Left word vs right particular category
+
+ 15 Right alphanum vs left particular category
+ 16 Right space vs left particular category
+ 17 Right word vs left particular category
+*/
+
+static const uint8_t propposstab[PT_TABSIZE][PT_TABSIZE] = {
+/* ANY LAMP GC PC SC ALNUM SPACE PXSPACE WORD CLIST UCNC */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_ANY */
+ { 0, 3, 0, 0, 0, 3, 1, 1, 0, 0, 0 }, /* PT_LAMP */
+ { 0, 0, 2, 4, 0, 9, 10, 10, 11, 0, 0 }, /* PT_GC */
+ { 0, 0, 5, 2, 0, 15, 16, 16, 17, 0, 0 }, /* PT_PC */
+ { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, /* PT_SC */
+ { 0, 3, 6, 12, 0, 3, 1, 1, 0, 0, 0 }, /* PT_ALNUM */
+ { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_SPACE */
+ { 0, 1, 7, 13, 0, 1, 3, 3, 1, 0, 0 }, /* PT_PXSPACE */
+ { 0, 0, 8, 14, 0, 0, 1, 1, 3, 0, 0 }, /* PT_WORD */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* PT_CLIST */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 } /* PT_UCNC */
+};
+
+/* This table is used to check whether auto-possessification is possible
+between adjacent Unicode property opcodes (OP_PROP and OP_NOTPROP) when one
+specifies a general category and the other specifies a particular category. The
+row is selected by the general category and the column by the particular
+category. The value is 1 if the particular category is not part of the general
+category. */
+
+static const uint8_t catposstab[7][30] = {
+/* Cc Cf Cn Co Cs Ll Lm Lo Lt Lu Mc Me Mn Nd Nl No Pc Pd Pe Pf Pi Po Ps Sc Sk Sm So Zl Zp Zs */
+ { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* C */
+ { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* L */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* M */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* N */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 }, /* P */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1 }, /* S */
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 } /* Z */
+};
+
+/* This table is used when checking ALNUM, (PX)SPACE, SPACE, and WORD against
+a general or particular category. The properties in each row are those
+that apply to the character set in question. Duplication means that a little
+unnecessary work is done when checking, but this keeps things much simpler
+because they can all use the same code. For more details see the comment where
+this table is used.
+
+Note: SPACE and PXSPACE used to be different because Perl excluded VT from
+"space", but from Perl 5.18 it's included, so both categories are treated the
+same here. */
+
+static const uint8_t posspropstab[3][4] = {
+ { ucp_L, ucp_N, ucp_N, ucp_Nl }, /* ALNUM, 3rd and 4th values redundant */
+ { ucp_Z, ucp_Z, ucp_C, ucp_Cc }, /* SPACE and PXSPACE, 2nd value redundant */
+ { ucp_L, ucp_N, ucp_P, ucp_Po } /* WORD */
+};
+#endif /* SUPPORT_UNICODE */
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+* Check a character and a property *
+*************************************************/
+
+/* This function is called by compare_opcodes() when a property item is
+adjacent to a fixed character.
+
+Arguments:
+ c the character
+ ptype the property type
+ pdata the data for the type
+ negated TRUE if it's a negated property (\P or \p{^)
+
+Returns: TRUE if auto-possessifying is OK
+*/
+
+static BOOL
+check_char_prop(uint32_t c, unsigned int ptype, unsigned int pdata,
+ BOOL negated)
+{
+const uint32_t *p;
+const ucd_record *prop = GET_UCD(c);
+
+switch(ptype)
+ {
+ case PT_LAMP:
+ return (prop->chartype == ucp_Lu ||
+ prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt) == negated;
+
+ case PT_GC:
+ return (pdata == PRIV(ucp_gentype)[prop->chartype]) == negated;
+
+ case PT_PC:
+ return (pdata == prop->chartype) == negated;
+
+ case PT_SC:
+ return (pdata == prop->script) == negated;
+
+ /* These are specials */
+
+ case PT_ALNUM:
+ return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N) == negated;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included, which
+ means that Perl space and POSIX space are now identical. PCRE was changed
+ at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ return negated;
+
+ default:
+ return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated;
+ }
+ break; /* Control never reaches here */
+
+ case PT_WORD:
+ return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ c == CHAR_UNDERSCORE) == negated;
+
+ case PT_CLIST:
+ p = PRIV(ucd_caseless_sets) + prop->caseset;
+ for (;;)
+ {
+ if (c < *p) return !negated;
+ if (c == *p++) return negated;
+ }
+ break; /* Control never reaches here */
+ }
+
+return FALSE;
+}
+#endif /* SUPPORT_UNICODE */
+
+
+
+/*************************************************
+* Base opcode of repeated opcodes *
+*************************************************/
+
+/* Returns the base opcode for repeated single character type opcodes. If the
+opcode is not a repeated character type, it returns with the original value.
+
+Arguments: c opcode
+Returns: base opcode for the type
+*/
+
+static PCRE2_UCHAR
+get_repeat_base(PCRE2_UCHAR c)
+{
+return (c > OP_TYPEPOSUPTO)? c :
+ (c >= OP_TYPESTAR)? OP_TYPESTAR :
+ (c >= OP_NOTSTARI)? OP_NOTSTARI :
+ (c >= OP_NOTSTAR)? OP_NOTSTAR :
+ (c >= OP_STARI)? OP_STARI :
+ OP_STAR;
+}
+
+
+/*************************************************
+* Fill the character property list *
+*************************************************/
+
+/* Checks whether the code points to an opcode that can take part in auto-
+possessification, and if so, fills a list with its properties.
+
+Arguments:
+ code points to start of expression
+ utf TRUE if in UTF mode
+ fcc points to the case-flipping table
+ list points to output list
+ list[0] will be filled with the opcode
+ list[1] will be non-zero if this opcode
+ can match an empty character string
+ list[2..7] depends on the opcode
+
+Returns: points to the start of the next opcode if *code is accepted
+ NULL if *code is not accepted
+*/
+
+static PCRE2_SPTR
+get_chr_property_list(PCRE2_SPTR code, BOOL utf, const uint8_t *fcc,
+ uint32_t *list)
+{
+PCRE2_UCHAR c = *code;
+PCRE2_UCHAR base;
+PCRE2_SPTR end;
+uint32_t chr;
+
+#ifdef SUPPORT_UNICODE
+uint32_t *clist_dest;
+const uint32_t *clist_src;
+#else
+(void)utf; /* Suppress "unused parameter" compiler warning */
+#endif
+
+list[0] = c;
+list[1] = FALSE;
+code++;
+
+if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+ {
+ base = get_repeat_base(c);
+ c -= (base - OP_STAR);
+
+ if (c == OP_UPTO || c == OP_MINUPTO || c == OP_EXACT || c == OP_POSUPTO)
+ code += IMM2_SIZE;
+
+ list[1] = (c != OP_PLUS && c != OP_MINPLUS && c != OP_EXACT &&
+ c != OP_POSPLUS);
+
+ switch(base)
+ {
+ case OP_STAR:
+ list[0] = OP_CHAR;
+ break;
+
+ case OP_STARI:
+ list[0] = OP_CHARI;
+ break;
+
+ case OP_NOTSTAR:
+ list[0] = OP_NOT;
+ break;
+
+ case OP_NOTSTARI:
+ list[0] = OP_NOTI;
+ break;
+
+ case OP_TYPESTAR:
+ list[0] = *code;
+ code++;
+ break;
+ }
+ c = list[0];
+ }
+
+switch(c)
+ {
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_ANYNL:
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ case OP_EXTUNI:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_DOLL:
+ case OP_DOLLM:
+ return code;
+
+ case OP_CHAR:
+ case OP_NOT:
+ GETCHARINCTEST(chr, code);
+ list[2] = chr;
+ list[3] = NOTACHAR;
+ return code;
+
+ case OP_CHARI:
+ case OP_NOTI:
+ list[0] = (c == OP_CHARI) ? OP_CHAR : OP_NOT;
+ GETCHARINCTEST(chr, code);
+ list[2] = chr;
+
+#ifdef SUPPORT_UNICODE
+ if (chr < 128 || (chr < 256 && !utf))
+ list[3] = fcc[chr];
+ else
+ list[3] = UCD_OTHERCASE(chr);
+#elif defined SUPPORT_WIDE_CHARS
+ list[3] = (chr < 256) ? fcc[chr] : chr;
+#else
+ list[3] = fcc[chr];
+#endif
+
+ /* The othercase might be the same value. */
+
+ if (chr == list[3])
+ list[3] = NOTACHAR;
+ else
+ list[4] = NOTACHAR;
+ return code;
+
+#ifdef SUPPORT_UNICODE
+ case OP_PROP:
+ case OP_NOTPROP:
+ if (code[0] != PT_CLIST)
+ {
+ list[2] = code[0];
+ list[3] = code[1];
+ return code + 2;
+ }
+
+ /* Convert only if we have enough space. */
+
+ clist_src = PRIV(ucd_caseless_sets) + code[1];
+ clist_dest = list + 2;
+ code += 2;
+
+ do {
+ if (clist_dest >= list + 8)
+ {
+ /* Early return if there is not enough space. This should never
+ happen, since all clists are shorter than 5 character now. */
+ list[2] = code[0];
+ list[3] = code[1];
+ return code;
+ }
+ *clist_dest++ = *clist_src;
+ }
+ while(*clist_src++ != NOTACHAR);
+
+ /* All characters are stored. The terminating NOTACHAR is copied from the
+ clist itself. */
+
+ list[0] = (c == OP_PROP) ? OP_CHAR : OP_NOT;
+ return code;
+#endif
+
+ case OP_NCLASS:
+ case OP_CLASS:
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ if (c == OP_XCLASS)
+ end = code + GET(code, 0) - 1;
+ else
+#endif
+ end = code + 32 / sizeof(PCRE2_UCHAR);
+
+ switch(*end)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSQUERY:
+ list[1] = TRUE;
+ end++;
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ end++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ list[1] = (GET2(end, 1) == 0);
+ end += 1 + 2 * IMM2_SIZE;
+ break;
+ }
+ list[2] = (uint32_t)(end - code);
+ return end;
+ }
+return NULL; /* Opcode not accepted */
+}
+
+
+
+/*************************************************
+* Scan further character sets for match *
+*************************************************/
+
+/* Checks whether the base and the current opcode have a common character, in
+which case the base cannot be possessified.
+
+Arguments:
+ code points to the byte code
+ utf TRUE in UTF mode
+ cb compile data block
+ base_list the data list of the base opcode
+ base_end the end of the base opcode
+ rec_limit points to recursion depth counter
+
+Returns: TRUE if the auto-possessification is possible
+*/
+
+static BOOL
+compare_opcodes(PCRE2_SPTR code, BOOL utf, const compile_block *cb,
+ const uint32_t *base_list, PCRE2_SPTR base_end, int *rec_limit)
+{
+PCRE2_UCHAR c;
+uint32_t list[8];
+const uint32_t *chr_ptr;
+const uint32_t *ochr_ptr;
+const uint32_t *list_ptr;
+PCRE2_SPTR next_code;
+#ifdef SUPPORT_WIDE_CHARS
+PCRE2_SPTR xclass_flags;
+#endif
+const uint8_t *class_bitset;
+const uint8_t *set1, *set2, *set_end;
+uint32_t chr;
+BOOL accepted, invert_bits;
+BOOL entered_a_group = FALSE;
+
+if (--(*rec_limit) <= 0) return FALSE; /* Recursion has gone too deep */
+
+/* Note: the base_list[1] contains whether the current opcode has a greedy
+(represented by a non-zero value) quantifier. This is a different from
+other character type lists, which store here that the character iterator
+matches to an empty string (also represented by a non-zero value). */
+
+for(;;)
+ {
+ /* All operations move the code pointer forward.
+ Therefore infinite recursions are not possible. */
+
+ c = *code;
+
+ /* Skip over callouts */
+
+ if (c == OP_CALLOUT)
+ {
+ code += PRIV(OP_lengths)[c];
+ continue;
+ }
+
+ if (c == OP_CALLOUT_STR)
+ {
+ code += GET(code, 1 + 2*LINK_SIZE);
+ continue;
+ }
+
+ /* At the end of a branch, skip to the end of the group. */
+
+ if (c == OP_ALT)
+ {
+ do code += GET(code, 1); while (*code == OP_ALT);
+ c = *code;
+ }
+
+ /* Inspect the next opcode. */
+
+ switch(c)
+ {
+ /* We can always possessify a greedy iterator at the end of the pattern,
+ which is reached after skipping over the final OP_KET. A non-greedy
+ iterator must never be possessified. */
+
+ case OP_END:
+ return base_list[1] != 0;
+
+ /* When an iterator is at the end of certain kinds of group we can inspect
+ what follows the group by skipping over the closing ket. Note that this
+ does not apply to OP_KETRMAX or OP_KETRMIN because what follows any given
+ iteration is variable (could be another iteration or could be the next
+ item). As these two opcodes are not listed in the next switch, they will
+ end up as the next code to inspect, and return FALSE by virtue of being
+ unsupported. */
+
+ case OP_KET:
+ case OP_KETRPOS:
+ /* The non-greedy case cannot be converted to a possessive form. */
+
+ if (base_list[1] == 0) return FALSE;
+
+ /* If the bracket is capturing it might be referenced by an OP_RECURSE
+ so its last iterator can never be possessified if the pattern contains
+ recursions. (This could be improved by keeping a list of group numbers that
+ are called by recursion.) */
+
+ switch(*(code - GET(code, 1)))
+ {
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ if (cb->had_recurse) return FALSE;
+ break;
+
+ /* Atomic sub-patterns and assertions can always auto-possessify their
+ last iterator. However, if the group was entered as a result of checking
+ a previous iterator, this is not possible. */
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+
+ return !entered_a_group;
+ }
+
+ /* Skip over the bracket and inspect what comes next. */
+
+ code += PRIV(OP_lengths)[c];
+ continue;
+
+ /* Handle cases where the next item is a group. */
+
+ case OP_ONCE:
+ case OP_BRA:
+ case OP_CBRA:
+ next_code = code + GET(code, 1);
+ code += PRIV(OP_lengths)[c];
+
+ /* Check each branch. We have to recurse a level for all but the last
+ branch. */
+
+ while (*next_code == OP_ALT)
+ {
+ if (!compare_opcodes(code, utf, cb, base_list, base_end, rec_limit))
+ return FALSE;
+ code = next_code + 1 + LINK_SIZE;
+ next_code += GET(next_code, 1);
+ }
+
+ entered_a_group = TRUE;
+ continue;
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+
+ next_code = code + 1;
+ if (*next_code != OP_BRA && *next_code != OP_CBRA &&
+ *next_code != OP_ONCE) return FALSE;
+
+ do next_code += GET(next_code, 1); while (*next_code == OP_ALT);
+
+ /* The bracket content will be checked by the OP_BRA/OP_CBRA case above. */
+
+ next_code += 1 + LINK_SIZE;
+ if (!compare_opcodes(next_code, utf, cb, base_list, base_end, rec_limit))
+ return FALSE;
+
+ code += PRIV(OP_lengths)[c];
+ continue;
+
+ /* The next opcode does not need special handling; fall through and use it
+ to see if the base can be possessified. */
+
+ default:
+ break;
+ }
+
+ /* We now have the next appropriate opcode to compare with the base. Check
+ for a supported opcode, and load its properties. */
+
+ code = get_chr_property_list(code, utf, cb->fcc, list);
+ if (code == NULL) return FALSE; /* Unsupported */
+
+ /* If either opcode is a small character list, set pointers for comparing
+ characters from that list with another list, or with a property. */
+
+ if (base_list[0] == OP_CHAR)
+ {
+ chr_ptr = base_list + 2;
+ list_ptr = list;
+ }
+ else if (list[0] == OP_CHAR)
+ {
+ chr_ptr = list + 2;
+ list_ptr = base_list;
+ }
+
+ /* Character bitsets can also be compared to certain opcodes. */
+
+ else if (base_list[0] == OP_CLASS || list[0] == OP_CLASS
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ /* In 8 bit, non-UTF mode, OP_CLASS and OP_NCLASS are the same. */
+ || (!utf && (base_list[0] == OP_NCLASS || list[0] == OP_NCLASS))
+#endif
+ )
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (base_list[0] == OP_CLASS || (!utf && base_list[0] == OP_NCLASS))
+#else
+ if (base_list[0] == OP_CLASS)
+#endif
+ {
+ set1 = (uint8_t *)(base_end - base_list[2]);
+ list_ptr = list;
+ }
+ else
+ {
+ set1 = (uint8_t *)(code - list[2]);
+ list_ptr = base_list;
+ }
+
+ invert_bits = FALSE;
+ switch(list_ptr[0])
+ {
+ case OP_CLASS:
+ case OP_NCLASS:
+ set2 = (uint8_t *)
+ ((list_ptr == list ? code : base_end) - list_ptr[2]);
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ xclass_flags = (list_ptr == list ? code : base_end) - list_ptr[2] + LINK_SIZE;
+ if ((*xclass_flags & XCL_HASPROP) != 0) return FALSE;
+ if ((*xclass_flags & XCL_MAP) == 0)
+ {
+ /* No bits are set for characters < 256. */
+ if (list[1] == 0) return (*xclass_flags & XCL_NOT) == 0;
+ /* Might be an empty repeat. */
+ continue;
+ }
+ set2 = (uint8_t *)(xclass_flags + 1);
+ break;
+#endif
+
+ case OP_NOT_DIGIT:
+ invert_bits = TRUE;
+ /* Fall through */
+ case OP_DIGIT:
+ set2 = (uint8_t *)(cb->cbits + cbit_digit);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ invert_bits = TRUE;
+ /* Fall through */
+ case OP_WHITESPACE:
+ set2 = (uint8_t *)(cb->cbits + cbit_space);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ invert_bits = TRUE;
+ /* Fall through */
+ case OP_WORDCHAR:
+ set2 = (uint8_t *)(cb->cbits + cbit_word);
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* Because the bit sets are unaligned bytes, we need to perform byte
+ comparison here. */
+
+ set_end = set1 + 32;
+ if (invert_bits)
+ {
+ do
+ {
+ if ((*set1++ & ~(*set2++)) != 0) return FALSE;
+ }
+ while (set1 < set_end);
+ }
+ else
+ {
+ do
+ {
+ if ((*set1++ & *set2++) != 0) return FALSE;
+ }
+ while (set1 < set_end);
+ }
+
+ if (list[1] == 0) return TRUE;
+ /* Might be an empty repeat. */
+ continue;
+ }
+
+ /* Some property combinations also acceptable. Unicode property opcodes are
+ processed specially; the rest can be handled with a lookup table. */
+
+ else
+ {
+ uint32_t leftop, rightop;
+
+ leftop = base_list[0];
+ rightop = list[0];
+
+#ifdef SUPPORT_UNICODE
+ accepted = FALSE; /* Always set in non-unicode case. */
+ if (leftop == OP_PROP || leftop == OP_NOTPROP)
+ {
+ if (rightop == OP_EOD)
+ accepted = TRUE;
+ else if (rightop == OP_PROP || rightop == OP_NOTPROP)
+ {
+ int n;
+ const uint8_t *p;
+ BOOL same = leftop == rightop;
+ BOOL lisprop = leftop == OP_PROP;
+ BOOL risprop = rightop == OP_PROP;
+ BOOL bothprop = lisprop && risprop;
+
+ /* There's a table that specifies how each combination is to be
+ processed:
+ 0 Always return FALSE (never auto-possessify)
+ 1 Character groups are distinct (possessify if both are OP_PROP)
+ 2 Check character categories in the same group (general or particular)
+ 3 Return TRUE if the two opcodes are not the same
+ ... see comments below
+ */
+
+ n = propposstab[base_list[2]][list[2]];
+ switch(n)
+ {
+ case 0: break;
+ case 1: accepted = bothprop; break;
+ case 2: accepted = (base_list[3] == list[3]) != same; break;
+ case 3: accepted = !same; break;
+
+ case 4: /* Left general category, right particular category */
+ accepted = risprop && catposstab[base_list[3]][list[3]] == same;
+ break;
+
+ case 5: /* Right general category, left particular category */
+ accepted = lisprop && catposstab[list[3]][base_list[3]] == same;
+ break;
+
+ /* This code is logically tricky. Think hard before fiddling with it.
+ The posspropstab table has four entries per row. Each row relates to
+ one of PCRE's special properties such as ALNUM or SPACE or WORD.
+ Only WORD actually needs all four entries, but using repeats for the
+ others means they can all use the same code below.
+
+ The first two entries in each row are Unicode general categories, and
+ apply always, because all the characters they include are part of the
+ PCRE character set. The third and fourth entries are a general and a
+ particular category, respectively, that include one or more relevant
+ characters. One or the other is used, depending on whether the check
+ is for a general or a particular category. However, in both cases the
+ category contains more characters than the specials that are defined
+ for the property being tested against. Therefore, it cannot be used
+ in a NOTPROP case.
+
+ Example: the row for WORD contains ucp_L, ucp_N, ucp_P, ucp_Po.
+ Underscore is covered by ucp_P or ucp_Po. */
+
+ case 6: /* Left alphanum vs right general category */
+ case 7: /* Left space vs right general category */
+ case 8: /* Left word vs right general category */
+ p = posspropstab[n-6];
+ accepted = risprop && lisprop ==
+ (list[3] != p[0] &&
+ list[3] != p[1] &&
+ (list[3] != p[2] || !lisprop));
+ break;
+
+ case 9: /* Right alphanum vs left general category */
+ case 10: /* Right space vs left general category */
+ case 11: /* Right word vs left general category */
+ p = posspropstab[n-9];
+ accepted = lisprop && risprop ==
+ (base_list[3] != p[0] &&
+ base_list[3] != p[1] &&
+ (base_list[3] != p[2] || !risprop));
+ break;
+
+ case 12: /* Left alphanum vs right particular category */
+ case 13: /* Left space vs right particular category */
+ case 14: /* Left word vs right particular category */
+ p = posspropstab[n-12];
+ accepted = risprop && lisprop ==
+ (catposstab[p[0]][list[3]] &&
+ catposstab[p[1]][list[3]] &&
+ (list[3] != p[3] || !lisprop));
+ break;
+
+ case 15: /* Right alphanum vs left particular category */
+ case 16: /* Right space vs left particular category */
+ case 17: /* Right word vs left particular category */
+ p = posspropstab[n-15];
+ accepted = lisprop && risprop ==
+ (catposstab[p[0]][base_list[3]] &&
+ catposstab[p[1]][base_list[3]] &&
+ (base_list[3] != p[3] || !risprop));
+ break;
+ }
+ }
+ }
+
+ else
+#endif /* SUPPORT_UNICODE */
+
+ accepted = leftop >= FIRST_AUTOTAB_OP && leftop <= LAST_AUTOTAB_LEFT_OP &&
+ rightop >= FIRST_AUTOTAB_OP && rightop <= LAST_AUTOTAB_RIGHT_OP &&
+ autoposstab[leftop - FIRST_AUTOTAB_OP][rightop - FIRST_AUTOTAB_OP];
+
+ if (!accepted) return FALSE;
+
+ if (list[1] == 0) return TRUE;
+ /* Might be an empty repeat. */
+ continue;
+ }
+
+ /* Control reaches here only if one of the items is a small character list.
+ All characters are checked against the other side. */
+
+ do
+ {
+ chr = *chr_ptr;
+
+ switch(list_ptr[0])
+ {
+ case OP_CHAR:
+ ochr_ptr = list_ptr + 2;
+ do
+ {
+ if (chr == *ochr_ptr) return FALSE;
+ ochr_ptr++;
+ }
+ while(*ochr_ptr != NOTACHAR);
+ break;
+
+ case OP_NOT:
+ ochr_ptr = list_ptr + 2;
+ do
+ {
+ if (chr == *ochr_ptr)
+ break;
+ ochr_ptr++;
+ }
+ while(*ochr_ptr != NOTACHAR);
+ if (*ochr_ptr == NOTACHAR) return FALSE; /* Not found */
+ break;
+
+ /* Note that OP_DIGIT etc. are generated only when PCRE2_UCP is *not*
+ set. When it is set, \d etc. are converted into OP_(NOT_)PROP codes. */
+
+ case OP_DIGIT:
+ if (chr < 256 && (cb->ctypes[chr] & ctype_digit) != 0) return FALSE;
+ break;
+
+ case OP_NOT_DIGIT:
+ if (chr > 255 || (cb->ctypes[chr] & ctype_digit) == 0) return FALSE;
+ break;
+
+ case OP_WHITESPACE:
+ if (chr < 256 && (cb->ctypes[chr] & ctype_space) != 0) return FALSE;
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (chr > 255 || (cb->ctypes[chr] & ctype_space) == 0) return FALSE;
+ break;
+
+ case OP_WORDCHAR:
+ if (chr < 255 && (cb->ctypes[chr] & ctype_word) != 0) return FALSE;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (chr > 255 || (cb->ctypes[chr] & ctype_word) == 0) return FALSE;
+ break;
+
+ case OP_HSPACE:
+ switch(chr)
+ {
+ HSPACE_CASES: return FALSE;
+ default: break;
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ switch(chr)
+ {
+ HSPACE_CASES: break;
+ default: return FALSE;
+ }
+ break;
+
+ case OP_ANYNL:
+ case OP_VSPACE:
+ switch(chr)
+ {
+ VSPACE_CASES: return FALSE;
+ default: break;
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ switch(chr)
+ {
+ VSPACE_CASES: break;
+ default: return FALSE;
+ }
+ break;
+
+ case OP_DOLL:
+ case OP_EODN:
+ switch (chr)
+ {
+ case CHAR_CR:
+ case CHAR_LF:
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ return FALSE;
+ }
+ break;
+
+ case OP_EOD: /* Can always possessify before \z */
+ break;
+
+#ifdef SUPPORT_UNICODE
+ case OP_PROP:
+ case OP_NOTPROP:
+ if (!check_char_prop(chr, list_ptr[2], list_ptr[3],
+ list_ptr[0] == OP_NOTPROP))
+ return FALSE;
+ break;
+#endif
+
+ case OP_NCLASS:
+ if (chr > 255) return FALSE;
+ /* Fall through */
+
+ case OP_CLASS:
+ if (chr > 255) break;
+ class_bitset = (uint8_t *)
+ ((list_ptr == list ? code : base_end) - list_ptr[2]);
+ if ((class_bitset[chr >> 3] & (1 << (chr & 7))) != 0) return FALSE;
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ if (PRIV(xclass)(chr, (list_ptr == list ? code : base_end) -
+ list_ptr[2] + LINK_SIZE, utf)) return FALSE;
+ break;
+#endif
+
+ default:
+ return FALSE;
+ }
+
+ chr_ptr++;
+ }
+ while(*chr_ptr != NOTACHAR);
+
+ /* At least one character must be matched from this opcode. */
+
+ if (list[1] == 0) return TRUE;
+ }
+
+/* Control never reaches here. There used to be a fail-save return FALSE; here,
+but some compilers complain about an unreachable statement. */
+}
+
+
+
+/*************************************************
+* Scan compiled regex for auto-possession *
+*************************************************/
+
+/* Replaces single character iterations with their possessive alternatives
+if appropriate. This function modifies the compiled opcode! Hitting a
+non-existent opcode may indicate a bug in PCRE2, but it can also be caused if a
+bad UTF string was compiled with PCRE2_NO_UTF_CHECK. The rec_limit catches
+overly complicated or large patterns. In these cases, the check just stops,
+leaving the remainder of the pattern unpossessified.
+
+Arguments:
+ code points to start of the byte code
+ utf TRUE in UTF mode
+ cb compile data block
+
+Returns: 0 for success
+ -1 if a non-existant opcode is encountered
+*/
+
+int
+PRIV(auto_possessify)(PCRE2_UCHAR *code, BOOL utf, const compile_block *cb)
+{
+PCRE2_UCHAR c;
+PCRE2_SPTR end;
+PCRE2_UCHAR *repeat_opcode;
+uint32_t list[8];
+int rec_limit = 1000; /* Was 10,000 but clang+ASAN uses a lot of stack. */
+
+for (;;)
+ {
+ c = *code;
+
+ if (c >= OP_TABLE_LENGTH) return -1; /* Something gone wrong */
+
+ if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
+ {
+ c -= get_repeat_base(c) - OP_STAR;
+ end = (c <= OP_MINUPTO) ?
+ get_chr_property_list(code, utf, cb->fcc, list) : NULL;
+ list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO;
+
+ if (end != NULL && compare_opcodes(end, utf, cb, list, end, &rec_limit))
+ {
+ switch(c)
+ {
+ case OP_STAR:
+ *code += OP_POSSTAR - OP_STAR;
+ break;
+
+ case OP_MINSTAR:
+ *code += OP_POSSTAR - OP_MINSTAR;
+ break;
+
+ case OP_PLUS:
+ *code += OP_POSPLUS - OP_PLUS;
+ break;
+
+ case OP_MINPLUS:
+ *code += OP_POSPLUS - OP_MINPLUS;
+ break;
+
+ case OP_QUERY:
+ *code += OP_POSQUERY - OP_QUERY;
+ break;
+
+ case OP_MINQUERY:
+ *code += OP_POSQUERY - OP_MINQUERY;
+ break;
+
+ case OP_UPTO:
+ *code += OP_POSUPTO - OP_UPTO;
+ break;
+
+ case OP_MINUPTO:
+ *code += OP_POSUPTO - OP_MINUPTO;
+ break;
+ }
+ }
+ c = *code;
+ }
+ else if (c == OP_CLASS || c == OP_NCLASS || c == OP_XCLASS)
+ {
+#ifdef SUPPORT_WIDE_CHARS
+ if (c == OP_XCLASS)
+ repeat_opcode = code + GET(code, 1);
+ else
+#endif
+ repeat_opcode = code + 1 + (32 / sizeof(PCRE2_UCHAR));
+
+ c = *repeat_opcode;
+ if (c >= OP_CRSTAR && c <= OP_CRMINRANGE)
+ {
+ /* end must not be NULL. */
+ end = get_chr_property_list(code, utf, cb->fcc, list);
+
+ list[1] = (c & 1) == 0;
+
+ if (compare_opcodes(end, utf, cb, list, end, &rec_limit))
+ {
+ switch (c)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ *repeat_opcode = OP_CRPOSSTAR;
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ *repeat_opcode = OP_CRPOSPLUS;
+ break;
+
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ *repeat_opcode = OP_CRPOSQUERY;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ *repeat_opcode = OP_CRPOSRANGE;
+ break;
+ }
+ }
+ }
+ c = *code;
+ }
+
+ switch(c)
+ {
+ case OP_END:
+ return 0;
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+ break;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSUPTO:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ code += 2;
+ break;
+
+ case OP_CALLOUT_STR:
+ code += GET(code, 1 + 2*LINK_SIZE);
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ code += GET(code, 1);
+ break;
+#endif
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ code += code[1];
+ break;
+ }
+
+ /* Add in the fixed length from the table */
+
+ code += PRIV(OP_lengths)[c];
+
+ /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be
+ followed by a multi-byte character. The length in the table is a minimum, so
+ we have to arrange to skip the extra code units. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf) switch(c)
+ {
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+ break;
+ }
+#else
+ (void)(utf); /* Keep compiler happy by referencing function argument */
+#endif /* SUPPORT_WIDE_CHARS */
+ }
+}
+
+/* End of pcre2_auto_possess.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_chartables.c b/test/monniaux/pcre2-10.32/pcre2_chartables.c
new file mode 100644
index 00000000..4046500c
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_chartables.c
@@ -0,0 +1,198 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* This file was automatically written by the dftables auxiliary
+program. It contains character tables that are used when no external
+tables are passed to PCRE2 by the application that calls it. The tables
+are used only for characters whose code values are less than 256. */
+
+/*The dftables program (which is distributed with PCRE2) can be used to
+build alternative versions of this file. This is necessary if you are
+running in an EBCDIC environment, or if you want to default to a different
+encoding, for example ISO-8859-1. When dftables is run, it creates these
+tables in the current locale. This happens automatically if PCRE2 is
+configured with --enable-rebuild-chartables. */
+
+/* The following #include is present because without it gcc 4.x may remove
+the array definition from the final binary if PCRE2 is built into a static
+library and dead code stripping is activated. This leads to link errors.
+Pulling in the header ensures that the array gets flagged as "someone
+outside this compilation unit might reference this" and so it will always
+be supplied to the linker. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+const uint8_t PRIV(default_tables)[] = {
+
+/* This table is a lower casing table. */
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,
+ 168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,
+ 184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,
+ 200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,
+ 232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255,
+
+/* This table is a case flipping table. */
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,
+ 168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,
+ 184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,
+ 200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,
+ 232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255,
+
+/* This table contains bit maps for various character classes. Each map is 32
+bytes long and the bits run from the least significant end of each byte. The
+classes that have their own maps are: space, xdigit, digit, upper, lower, word,
+graph print, punct, and cntrl. Other classes are built from combinations. */
+
+ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
+ 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+/* This table identifies various classes of character by individual bits:
+ 0x01 white space character
+ 0x02 letter
+ 0x04 decimal digit
+ 0x08 hexadecimal digit
+ 0x10 alphanumeric or '_'
+*/
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
+ 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
+ 0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* - ' */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* ( - / */
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
+ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x00, /* 8 - ? */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
+ 0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x10, /* X - _ */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
+ 0x12,0x12,0x12,0x00,0x00,0x00,0x00,0x00, /* x -127 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+/* End of pcre2_chartables.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_compile.c b/test/monniaux/pcre2-10.32/pcre2_compile.c
new file mode 100644
index 00000000..6bb1de36
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_compile.c
@@ -0,0 +1,9921 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NLBLOCK cb /* Block containing newline information */
+#define PSSTART start_pattern /* Field containing processed string start */
+#define PSEND end_pattern /* Field containing processed string end */
+
+#include "pcre2_internal.h"
+
+/* In rare error cases debugging might require calling pcre2_printint(). */
+
+#if 0
+#ifdef EBCDIC
+#define PRINTABLE(c) ((c) >= 64 && (c) < 255)
+#else
+#define PRINTABLE(c) ((c) >= 32 && (c) < 127)
+#endif
+#include "pcre2_printint.c"
+#define DEBUG_CALL_PRINTINT
+#endif
+
+/* Other debugging code can be enabled by these defines. */
+
+/* #define DEBUG_SHOW_CAPTURES */
+/* #define DEBUG_SHOW_PARSED */
+
+/* There are a few things that vary with different code unit sizes. Handle them
+by defining macros in order to minimize #if usage. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define STRING_UTFn_RIGHTPAR STRING_UTF8_RIGHTPAR, 5
+#define XDIGIT(c) xdigitab[c]
+
+#else /* Either 16-bit or 32-bit */
+#define XDIGIT(c) (MAX_255(c)? xdigitab[c] : 0xff)
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+#define STRING_UTFn_RIGHTPAR STRING_UTF16_RIGHTPAR, 6
+
+#else /* 32-bit */
+#define STRING_UTFn_RIGHTPAR STRING_UTF32_RIGHTPAR, 6
+#endif
+#endif
+
+/* Macros to store and retrieve a PCRE2_SIZE value in the parsed pattern, which
+consists of uint32_t elements. Assume that if uint32_t can't hold it, two of
+them will be able to (i.e. assume a 64-bit world). */
+
+#if PCRE2_SIZE_MAX <= UINT32_MAX
+#define PUTOFFSET(s,p) *p++ = s
+#define GETOFFSET(s,p) s = *p++
+#define GETPLUSOFFSET(s,p) s = *(++p)
+#define READPLUSOFFSET(s,p) s = p[1]
+#define SKIPOFFSET(p) p++
+#define SIZEOFFSET 1
+#else
+#define PUTOFFSET(s,p) \
+ { *p++ = (uint32_t)(s >> 32); *p++ = (uint32_t)(s & 0xffffffff); }
+#define GETOFFSET(s,p) \
+ { s = ((PCRE2_SIZE)p[0] << 32) | (PCRE2_SIZE)p[1]; p += 2; }
+#define GETPLUSOFFSET(s,p) \
+ { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; p += 2; }
+#define READPLUSOFFSET(s,p) \
+ { s = ((PCRE2_SIZE)p[1] << 32) | (PCRE2_SIZE)p[2]; }
+#define SKIPOFFSET(p) p += 2
+#define SIZEOFFSET 2
+#endif
+
+/* Macros for manipulating elements of the parsed pattern vector. */
+
+#define META_CODE(x) (x & 0xffff0000u)
+#define META_DATA(x) (x & 0x0000ffffu)
+#define META_DIFF(x,y) ((x-y)>>16)
+
+/* Function definitions to allow mutual recursion */
+
+#ifdef SUPPORT_UNICODE
+static unsigned int
+ add_list_to_class_internal(uint8_t *, PCRE2_UCHAR **, uint32_t,
+ compile_block *, const uint32_t *, unsigned int);
+#endif
+
+static int
+ compile_regex(uint32_t, PCRE2_UCHAR **, uint32_t **, int *, uint32_t,
+ uint32_t *, int32_t *, uint32_t *, int32_t *, branch_chain *,
+ compile_block *, PCRE2_SIZE *);
+
+static int
+ get_branchlength(uint32_t **, int *, int *, parsed_recurse_check *,
+ compile_block *);
+
+static BOOL
+ set_lookbehind_lengths(uint32_t **, int *, int *, parsed_recurse_check *,
+ compile_block *);
+
+
+
+/*************************************************
+* Code parameters and static tables *
+*************************************************/
+
+#define MAX_GROUP_NUMBER 65535u
+#define MAX_REPEAT_COUNT 65535u
+#define REPEAT_UNLIMITED (MAX_REPEAT_COUNT+1)
+
+/* COMPILE_WORK_SIZE specifies the size of stack workspace, which is used in
+different ways in the different pattern scans. The parsing and group-
+identifying pre-scan uses it to handle nesting, and needs it to be 16-bit
+aligned for this. Having defined the size in code units, we set up
+C16_WORK_SIZE as the number of elements in the 16-bit vector.
+
+During the first compiling phase, when determining how much memory is required,
+the regex is partly compiled into this space, but the compiled parts are
+discarded as soon as they can be, so that hopefully there will never be an
+overrun. The code does, however, check for an overrun, which can occur for
+pathological patterns. The size of the workspace depends on LINK_SIZE because
+the length of compiled items varies with this.
+
+In the real compile phase, this workspace is not currently used. */
+
+#define COMPILE_WORK_SIZE (3000*LINK_SIZE) /* Size in code units */
+
+#define C16_WORK_SIZE \
+ ((COMPILE_WORK_SIZE * sizeof(PCRE2_UCHAR))/sizeof(uint16_t))
+
+/* A uint32_t vector is used for caching information about the size of
+capturing groups, to improve performance. A default is created on the stack of
+this size. */
+
+#define GROUPINFO_DEFAULT_SIZE 256
+
+/* The overrun tests check for a slightly smaller size so that they detect the
+overrun before it actually does run off the end of the data block. */
+
+#define WORK_SIZE_SAFETY_MARGIN (100)
+
+/* This value determines the size of the initial vector that is used for
+remembering named groups during the pre-compile. It is allocated on the stack,
+but if it is too small, it is expanded, in a similar way to the workspace. The
+value is the number of slots in the list. */
+
+#define NAMED_GROUP_LIST_SIZE 20
+
+/* The pre-compiling pass over the pattern creates a parsed pattern in a vector
+of uint32_t. For short patterns this lives on the stack, with this size. Heap
+memory is used for longer patterns. */
+
+#define PARSED_PATTERN_DEFAULT_SIZE 1024
+
+/* Maximum length value to check against when making sure that the variable
+that holds the compiled pattern length does not overflow. We make it a bit less
+than INT_MAX to allow for adding in group terminating code units, so that we
+don't have to check them every time. */
+
+#define OFLOW_MAX (INT_MAX - 20)
+
+/* Code values for parsed patterns, which are stored in a vector of 32-bit
+unsigned ints. Values less than META_END are literal data values. The coding
+for identifying the item is in the top 16-bits, leaving 16 bits for the
+additional data that some of them need. The META_CODE, META_DATA, and META_DIFF
+macros are used to manipulate parsed pattern elements.
+
+NOTE: When these definitions are changed, the table of extra lengths for each
+code (meta_extra_lengths, just below) must be updated to remain in step. */
+
+#define META_END 0x80000000u /* End of pattern */
+
+#define META_ALT 0x80010000u /* alternation */
+#define META_ATOMIC 0x80020000u /* atomic group */
+#define META_BACKREF 0x80030000u /* Back ref */
+#define META_BACKREF_BYNAME 0x80040000u /* \k'name' */
+#define META_BIGVALUE 0x80050000u /* Next is a literal > META_END */
+#define META_CALLOUT_NUMBER 0x80060000u /* (?C with numerical argument */
+#define META_CALLOUT_STRING 0x80070000u /* (?C with string argument */
+#define META_CAPTURE 0x80080000u /* Capturing parenthesis */
+#define META_CIRCUMFLEX 0x80090000u /* ^ metacharacter */
+#define META_CLASS 0x800a0000u /* start non-empty class */
+#define META_CLASS_EMPTY 0x800b0000u /* empty class */
+#define META_CLASS_EMPTY_NOT 0x800c0000u /* negative empty class */
+#define META_CLASS_END 0x800d0000u /* end of non-empty class */
+#define META_CLASS_NOT 0x800e0000u /* start non-empty negative class */
+#define META_COND_ASSERT 0x800f0000u /* (?(?assertion)... */
+#define META_COND_DEFINE 0x80100000u /* (?(DEFINE)... */
+#define META_COND_NAME 0x80110000u /* (?(<name>)... */
+#define META_COND_NUMBER 0x80120000u /* (?(digits)... */
+#define META_COND_RNAME 0x80130000u /* (?(R&name)... */
+#define META_COND_RNUMBER 0x80140000u /* (?(Rdigits)... */
+#define META_COND_VERSION 0x80150000u /* (?(VERSION<op>x.y)... */
+#define META_DOLLAR 0x80160000u /* $ metacharacter */
+#define META_DOT 0x80170000u /* . metacharacter */
+#define META_ESCAPE 0x80180000u /* \d and friends */
+#define META_KET 0x80190000u /* closing parenthesis */
+#define META_NOCAPTURE 0x801a0000u /* no capture parens */
+#define META_OPTIONS 0x801b0000u /* (?i) and friends */
+#define META_POSIX 0x801c0000u /* POSIX class item */
+#define META_POSIX_NEG 0x801d0000u /* negative POSIX class item */
+#define META_RANGE_ESCAPED 0x801e0000u /* range with at least one escape */
+#define META_RANGE_LITERAL 0x801f0000u /* range defined literally */
+#define META_RECURSE 0x80200000u /* Recursion */
+#define META_RECURSE_BYNAME 0x80210000u /* (?&name) */
+
+/* These must be kept together to make it easy to check that an assertion
+is present where expected in a conditional group. */
+
+#define META_LOOKAHEAD 0x80220000u /* (?= */
+#define META_LOOKAHEADNOT 0x80230000u /* (?! */
+#define META_LOOKBEHIND 0x80240000u /* (?<= */
+#define META_LOOKBEHINDNOT 0x80250000u /* (?<! */
+
+/* These must be kept in this order, with consecutive values, and the _ARG
+versions of COMMIT, PRUNE, SKIP, and THEN immediately after their non-argument
+versions. */
+
+#define META_MARK 0x80260000u /* (*MARK) */
+#define META_ACCEPT 0x80270000u /* (*ACCEPT) */
+#define META_FAIL 0x80280000u /* (*FAIL) */
+#define META_COMMIT 0x80290000u /* These */
+#define META_COMMIT_ARG 0x802a0000u /* pairs */
+#define META_PRUNE 0x802b0000u /* must */
+#define META_PRUNE_ARG 0x802c0000u /* be */
+#define META_SKIP 0x802d0000u /* kept */
+#define META_SKIP_ARG 0x802e0000u /* in */
+#define META_THEN 0x802f0000u /* this */
+#define META_THEN_ARG 0x80300000u /* order */
+
+/* These must be kept in groups of adjacent 3 values, and all together. */
+
+#define META_ASTERISK 0x80310000u /* * */
+#define META_ASTERISK_PLUS 0x80320000u /* *+ */
+#define META_ASTERISK_QUERY 0x80330000u /* *? */
+#define META_PLUS 0x80340000u /* + */
+#define META_PLUS_PLUS 0x80350000u /* ++ */
+#define META_PLUS_QUERY 0x80360000u /* +? */
+#define META_QUERY 0x80370000u /* ? */
+#define META_QUERY_PLUS 0x80380000u /* ?+ */
+#define META_QUERY_QUERY 0x80390000u /* ?? */
+#define META_MINMAX 0x803a0000u /* {n,m} repeat */
+#define META_MINMAX_PLUS 0x803b0000u /* {n,m}+ repeat */
+#define META_MINMAX_QUERY 0x803c0000u /* {n,m}? repeat */
+
+#define META_FIRST_QUANTIFIER META_ASTERISK
+#define META_LAST_QUANTIFIER META_MINMAX_QUERY
+
+/* Table of extra lengths for each of the meta codes. Must be kept in step with
+the definitions above. For some items these values are a basic length to which
+a variable amount has to be added. */
+
+static unsigned char meta_extra_lengths[] = {
+ 0, /* META_END */
+ 0, /* META_ALT */
+ 0, /* META_ATOMIC */
+ 0, /* META_BACKREF - more if group is >= 10 */
+ 1+SIZEOFFSET, /* META_BACKREF_BYNAME */
+ 1, /* META_BIGVALUE */
+ 3, /* META_CALLOUT_NUMBER */
+ 3+SIZEOFFSET, /* META_CALLOUT_STRING */
+ 0, /* META_CAPTURE */
+ 0, /* META_CIRCUMFLEX */
+ 0, /* META_CLASS */
+ 0, /* META_CLASS_EMPTY */
+ 0, /* META_CLASS_EMPTY_NOT */
+ 0, /* META_CLASS_END */
+ 0, /* META_CLASS_NOT */
+ 0, /* META_COND_ASSERT */
+ SIZEOFFSET, /* META_COND_DEFINE */
+ 1+SIZEOFFSET, /* META_COND_NAME */
+ 1+SIZEOFFSET, /* META_COND_NUMBER */
+ 1+SIZEOFFSET, /* META_COND_RNAME */
+ 1+SIZEOFFSET, /* META_COND_RNUMBER */
+ 3, /* META_COND_VERSION */
+ 0, /* META_DOLLAR */
+ 0, /* META_DOT */
+ 0, /* META_ESCAPE - more for ESC_P, ESC_p, ESC_g, ESC_k */
+ 0, /* META_KET */
+ 0, /* META_NOCAPTURE */
+ 1, /* META_OPTIONS */
+ 1, /* META_POSIX */
+ 1, /* META_POSIX_NEG */
+ 0, /* META_RANGE_ESCAPED */
+ 0, /* META_RANGE_LITERAL */
+ SIZEOFFSET, /* META_RECURSE */
+ 1+SIZEOFFSET, /* META_RECURSE_BYNAME */
+ 0, /* META_LOOKAHEAD */
+ 0, /* META_LOOKAHEADNOT */
+ SIZEOFFSET, /* META_LOOKBEHIND */
+ SIZEOFFSET, /* META_LOOKBEHINDNOT */
+ 1, /* META_MARK - plus the string length */
+ 0, /* META_ACCEPT */
+ 0, /* META_FAIL */
+ 0, /* META_COMMIT */
+ 1, /* META_COMMIT_ARG - plus the string length */
+ 0, /* META_PRUNE */
+ 1, /* META_PRUNE_ARG - plus the string length */
+ 0, /* META_SKIP */
+ 1, /* META_SKIP_ARG - plus the string length */
+ 0, /* META_THEN */
+ 1, /* META_THEN_ARG - plus the string length */
+ 0, /* META_ASTERISK */
+ 0, /* META_ASTERISK_PLUS */
+ 0, /* META_ASTERISK_QUERY */
+ 0, /* META_PLUS */
+ 0, /* META_PLUS_PLUS */
+ 0, /* META_PLUS_QUERY */
+ 0, /* META_QUERY */
+ 0, /* META_QUERY_PLUS */
+ 0, /* META_QUERY_QUERY */
+ 2, /* META_MINMAX */
+ 2, /* META_MINMAX_PLUS */
+ 2 /* META_MINMAX_QUERY */
+};
+
+/* Types for skipping parts of a parsed pattern. */
+
+enum { PSKIP_ALT, PSKIP_CLASS, PSKIP_KET };
+
+/* Macro for setting individual bits in class bitmaps. It took some
+experimenting to figure out how to stop gcc 5.3.0 from warning with
+-Wconversion. This version gets a warning:
+
+ #define SETBIT(a,b) a[(b)/8] |= (uint8_t)(1 << ((b)&7))
+
+Let's hope the apparently less efficient version isn't actually so bad if the
+compiler is clever with identical subexpressions. */
+
+#define SETBIT(a,b) a[(b)/8] = (uint8_t)(a[(b)/8] | (1 << ((b)&7)))
+
+/* Private flags added to firstcu and reqcu. */
+
+#define REQ_CASELESS (1 << 0) /* Indicates caselessness */
+#define REQ_VARY (1 << 1) /* reqcu followed non-literal item */
+/* Negative values for the firstcu and reqcu flags */
+#define REQ_UNSET (-2) /* Not yet found anything */
+#define REQ_NONE (-1) /* Found not fixed char */
+
+/* These flags are used in the groupinfo vector. */
+
+#define GI_SET_FIXED_LENGTH 0x80000000u
+#define GI_NOT_FIXED_LENGTH 0x40000000u
+#define GI_FIXED_LENGTH_MASK 0x0000ffffu
+
+/* This simple test for a decimal digit works for both ASCII/Unicode and EBCDIC
+and is fast (a good compiler can turn it into a subtraction and unsigned
+comparison). */
+
+#define IS_DIGIT(x) ((x) >= CHAR_0 && (x) <= CHAR_9)
+
+/* Table to identify hex digits. The tables in chartables are dependent on the
+locale, and may mark arbitrary characters as digits. We want to recognize only
+0-9, a-z, and A-Z as hex digits, which is why we have a private table here. It
+costs 256 bytes, but it is a lot faster than doing character value tests (at
+least in some simple cases I timed), and in some applications one wants PCRE2
+to compile efficiently as well as match efficiently. The value in the table is
+the binary hex digit value, or 0xff for non-hex digits. */
+
+/* This is the "normal" case, for ASCII systems, and EBCDIC systems running in
+UTF-8 mode. */
+
+#ifndef EBCDIC
+static const uint8_t xdigitab[] =
+ {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - ' */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ( - / */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 */
+ 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff, /* 8 - ? */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* @ - G */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H - O */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* P - W */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* X - _ */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* ` - g */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h - o */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* p - w */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* x -127 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 128-135 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 136-143 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144-151 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 152-159 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160-167 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 168-175 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 176-183 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 192-199 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 2ff-207 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 208-215 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 216-223 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 224-231 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 232-239 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 240-247 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};/* 248-255 */
+
+#else
+
+/* This is the "abnormal" case, for EBCDIC systems not running in UTF-8 mode. */
+
+static const uint8_t xdigitab[] =
+ {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 0- 7 0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 8- 15 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 16- 23 10 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 24- 31 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 32- 39 20 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 40- 47 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 48- 55 30 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 56- 63 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - 71 40 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 72- | */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* & - 87 50 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 88- 95 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* - -103 60 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 104- ? */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 112-119 70 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 120- " */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* 128- g 80 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* h -143 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 144- p 90 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* q -159 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 160- x A0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* y -175 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* ^ -183 B0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* 184-191 */
+ 0xff,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xff, /* { - G C0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* H -207 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* } - P D0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Q -223 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* \ - X E0 */
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, /* Y -239 */
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, /* 0 - 7 F0 */
+ 0x08,0x09,0xff,0xff,0xff,0xff,0xff,0xff};/* 8 -255 */
+#endif /* EBCDIC */
+
+
+/* Table for handling alphanumeric escaped characters. Positive returns are
+simple data values; negative values are for special things like \d and so on.
+Zero means further processing is needed (for things like \x), or the escape is
+invalid. */
+
+/* This is the "normal" table for ASCII systems or for EBCDIC systems running
+in UTF-8 mode. It runs from '0' to 'z'. */
+
+#ifndef EBCDIC
+#define ESCAPES_FIRST CHAR_0
+#define ESCAPES_LAST CHAR_z
+#define UPPER_CASE(c) (c-32)
+
+static const short int escapes[] = {
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ CHAR_COLON, CHAR_SEMICOLON,
+ CHAR_LESS_THAN_SIGN, CHAR_EQUALS_SIGN,
+ CHAR_GREATER_THAN_SIGN, CHAR_QUESTION_MARK,
+ CHAR_COMMERCIAL_AT, -ESC_A,
+ -ESC_B, -ESC_C,
+ -ESC_D, -ESC_E,
+ 0, -ESC_G,
+ -ESC_H, 0,
+ 0, -ESC_K,
+ 0, 0,
+ -ESC_N, 0,
+ -ESC_P, -ESC_Q,
+ -ESC_R, -ESC_S,
+ 0, 0,
+ -ESC_V, -ESC_W,
+ -ESC_X, 0,
+ -ESC_Z, CHAR_LEFT_SQUARE_BRACKET,
+ CHAR_BACKSLASH, CHAR_RIGHT_SQUARE_BRACKET,
+ CHAR_CIRCUMFLEX_ACCENT, CHAR_UNDERSCORE,
+ CHAR_GRAVE_ACCENT, CHAR_BEL,
+ -ESC_b, 0,
+ -ESC_d, CHAR_ESC,
+ CHAR_FF, 0,
+ -ESC_h, 0,
+ 0, -ESC_k,
+ 0, 0,
+ CHAR_LF, 0,
+ -ESC_p, 0,
+ CHAR_CR, -ESC_s,
+ CHAR_HT, 0,
+ -ESC_v, -ESC_w,
+ 0, 0,
+ -ESC_z
+};
+
+#else
+
+/* This is the "abnormal" table for EBCDIC systems without UTF-8 support.
+It runs from 'a' to '9'. For some minimal testing of EBCDIC features, the code
+is sometimes compiled on an ASCII system. In this case, we must not use CHAR_a
+because it is defined as 'a', which of course picks up the ASCII value. */
+
+#if 'a' == 0x81 /* Check for a real EBCDIC environment */
+#define ESCAPES_FIRST CHAR_a
+#define ESCAPES_LAST CHAR_9
+#define UPPER_CASE(c) (c+64)
+#else /* Testing in an ASCII environment */
+#define ESCAPES_FIRST ((unsigned char)'\x81') /* EBCDIC 'a' */
+#define ESCAPES_LAST ((unsigned char)'\xf9') /* EBCDIC '9' */
+#define UPPER_CASE(c) (c-32)
+#endif
+
+static const short int escapes[] = {
+/* 80 */ CHAR_BEL, -ESC_b, 0, -ESC_d, CHAR_ESC, CHAR_FF, 0,
+/* 88 */ -ESC_h, 0, 0, '{', 0, 0, 0, 0,
+/* 90 */ 0, 0, -ESC_k, 0, 0, CHAR_LF, 0, -ESC_p,
+/* 98 */ 0, CHAR_CR, 0, '}', 0, 0, 0, 0,
+/* A0 */ 0, '~', -ESC_s, CHAR_HT, 0, -ESC_v, -ESC_w, 0,
+/* A8 */ 0, -ESC_z, 0, 0, 0, '[', 0, 0,
+/* B0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* B8 */ 0, 0, 0, 0, 0, ']', '=', '-',
+/* C0 */ '{', -ESC_A, -ESC_B, -ESC_C, -ESC_D, -ESC_E, 0, -ESC_G,
+/* C8 */ -ESC_H, 0, 0, 0, 0, 0, 0, 0,
+/* D0 */ '}', 0, -ESC_K, 0, 0, -ESC_N, 0, -ESC_P,
+/* D8 */ -ESC_Q, -ESC_R, 0, 0, 0, 0, 0, 0,
+/* E0 */ '\\', 0, -ESC_S, 0, 0, -ESC_V, -ESC_W, -ESC_X,
+/* E8 */ 0, -ESC_Z, 0, 0, 0, 0, 0, 0,
+/* F0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* F8 */ 0, 0
+};
+
+/* We also need a table of characters that may follow \c in an EBCDIC
+environment for characters 0-31. */
+
+static unsigned char ebcdic_escape_c[] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
+
+#endif /* EBCDIC */
+
+
+/* Table of special "verbs" like (*PRUNE). This is a short table, so it is
+searched linearly. Put all the names into a single string, in order to reduce
+the number of relocations when a shared library is dynamically linked. The
+string is built from string macros so that it works in UTF-8 mode on EBCDIC
+platforms. */
+
+typedef struct verbitem {
+ unsigned int len; /* Length of verb name */
+ uint32_t meta; /* Base META_ code */
+ int has_arg; /* Argument requirement */
+} verbitem;
+
+static const char verbnames[] =
+ "\0" /* Empty name is a shorthand for MARK */
+ STRING_MARK0
+ STRING_ACCEPT0
+ STRING_F0
+ STRING_FAIL0
+ STRING_COMMIT0
+ STRING_PRUNE0
+ STRING_SKIP0
+ STRING_THEN;
+
+static const verbitem verbs[] = {
+ { 0, META_MARK, +1 }, /* > 0 => must have an argument */
+ { 4, META_MARK, +1 },
+ { 6, META_ACCEPT, -1 }, /* < 0 => Optional argument, convert to pre-MARK */
+ { 1, META_FAIL, -1 },
+ { 4, META_FAIL, -1 },
+ { 6, META_COMMIT, 0 },
+ { 5, META_PRUNE, 0 }, /* Optional argument; bump META code if found */
+ { 4, META_SKIP, 0 },
+ { 4, META_THEN, 0 }
+};
+
+static const int verbcount = sizeof(verbs)/sizeof(verbitem);
+
+/* Verb opcodes, indexed by their META code offset from META_MARK. */
+
+static const uint32_t verbops[] = {
+ OP_MARK, OP_ACCEPT, OP_FAIL, OP_COMMIT, OP_COMMIT_ARG, OP_PRUNE,
+ OP_PRUNE_ARG, OP_SKIP, OP_SKIP_ARG, OP_THEN, OP_THEN_ARG };
+
+/* Offsets from OP_STAR for case-independent and negative repeat opcodes. */
+
+static uint32_t chartypeoffset[] = {
+ OP_STAR - OP_STAR, OP_STARI - OP_STAR,
+ OP_NOTSTAR - OP_STAR, OP_NOTSTARI - OP_STAR };
+
+/* Tables of names of POSIX character classes and their lengths. The names are
+now all in a single string, to reduce the number of relocations when a shared
+library is dynamically loaded. The list of lengths is terminated by a zero
+length entry. The first three must be alpha, lower, upper, as this is assumed
+for handling case independence. The indices for graph, print, and punct are
+needed, so identify them. */
+
+static const char posix_names[] =
+ STRING_alpha0 STRING_lower0 STRING_upper0 STRING_alnum0
+ STRING_ascii0 STRING_blank0 STRING_cntrl0 STRING_digit0
+ STRING_graph0 STRING_print0 STRING_punct0 STRING_space0
+ STRING_word0 STRING_xdigit;
+
+static const uint8_t posix_name_lengths[] = {
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 6, 0 };
+
+#define PC_GRAPH 8
+#define PC_PRINT 9
+#define PC_PUNCT 10
+
+/* Table of class bit maps for each POSIX class. Each class is formed from a
+base map, with an optional addition or removal of another map. Then, for some
+classes, there is some additional tweaking: for [:blank:] the vertical space
+characters are removed, and for [:alpha:] and [:alnum:] the underscore
+character is removed. The triples in the table consist of the base map offset,
+second map offset or -1 if no second map, and a non-negative value for map
+addition or a negative value for map subtraction (if there are two maps). The
+absolute value of the third field has these meanings: 0 => no tweaking, 1 =>
+remove vertical space characters, 2 => remove underscore. */
+
+static const int posix_class_maps[] = {
+ cbit_word, cbit_digit, -2, /* alpha */
+ cbit_lower, -1, 0, /* lower */
+ cbit_upper, -1, 0, /* upper */
+ cbit_word, -1, 2, /* alnum - word without underscore */
+ cbit_print, cbit_cntrl, 0, /* ascii */
+ cbit_space, -1, 1, /* blank - a GNU extension */
+ cbit_cntrl, -1, 0, /* cntrl */
+ cbit_digit, -1, 0, /* digit */
+ cbit_graph, -1, 0, /* graph */
+ cbit_print, -1, 0, /* print */
+ cbit_punct, -1, 0, /* punct */
+ cbit_space, -1, 0, /* space */
+ cbit_word, -1, 0, /* word - a Perl extension */
+ cbit_xdigit,-1, 0 /* xdigit */
+};
+
+#ifdef SUPPORT_UNICODE
+
+/* The POSIX class Unicode property substitutes that are used in UCP mode must
+be in the order of the POSIX class names, defined above. */
+
+static int posix_substitutes[] = {
+ PT_GC, ucp_L, /* alpha */
+ PT_PC, ucp_Ll, /* lower */
+ PT_PC, ucp_Lu, /* upper */
+ PT_ALNUM, 0, /* alnum */
+ -1, 0, /* ascii, treat as non-UCP */
+ -1, 1, /* blank, treat as \h */
+ PT_PC, ucp_Cc, /* cntrl */
+ PT_PC, ucp_Nd, /* digit */
+ PT_PXGRAPH, 0, /* graph */
+ PT_PXPRINT, 0, /* print */
+ PT_PXPUNCT, 0, /* punct */
+ PT_PXSPACE, 0, /* space */ /* Xps is POSIX space, but from 8.34 */
+ PT_WORD, 0, /* word */ /* Perl and POSIX space are the same */
+ -1, 0 /* xdigit, treat as non-UCP */
+};
+#define POSIX_SUBSIZE (sizeof(posix_substitutes) / (2*sizeof(uint32_t)))
+#endif /* SUPPORT_UNICODE */
+
+/* Masks for checking option settings. When PCRE2_LITERAL is set, only a subset
+are allowed. */
+
+#define PUBLIC_LITERAL_COMPILE_OPTIONS \
+ (PCRE2_ANCHORED|PCRE2_AUTO_CALLOUT|PCRE2_CASELESS|PCRE2_ENDANCHORED| \
+ PCRE2_FIRSTLINE|PCRE2_LITERAL|PCRE2_NO_START_OPTIMIZE| \
+ PCRE2_NO_UTF_CHECK|PCRE2_USE_OFFSET_LIMIT|PCRE2_UTF)
+
+#define PUBLIC_COMPILE_OPTIONS \
+ (PUBLIC_LITERAL_COMPILE_OPTIONS| \
+ PCRE2_ALLOW_EMPTY_CLASS|PCRE2_ALT_BSUX|PCRE2_ALT_CIRCUMFLEX| \
+ PCRE2_ALT_VERBNAMES|PCRE2_DOLLAR_ENDONLY|PCRE2_DOTALL|PCRE2_DUPNAMES| \
+ PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MATCH_UNSET_BACKREF| \
+ PCRE2_MULTILINE|PCRE2_NEVER_BACKSLASH_C|PCRE2_NEVER_UCP| \
+ PCRE2_NEVER_UTF|PCRE2_NO_AUTO_CAPTURE|PCRE2_NO_AUTO_POSSESS| \
+ PCRE2_NO_DOTSTAR_ANCHOR|PCRE2_UCP|PCRE2_UNGREEDY)
+
+#define PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS \
+ (PCRE2_EXTRA_MATCH_LINE|PCRE2_EXTRA_MATCH_WORD)
+
+#define PUBLIC_COMPILE_EXTRA_OPTIONS \
+ (PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS| \
+ PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES|PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL)
+
+/* Compile time error code numbers. They are given names so that they can more
+easily be tracked. When a new number is added, the tables called eint1 and
+eint2 in pcre2posix.c may need to be updated, and a new error text must be
+added to compile_error_texts in pcre2_error.c. */
+
+enum { ERR0 = COMPILE_ERROR_BASE,
+ ERR1, ERR2, ERR3, ERR4, ERR5, ERR6, ERR7, ERR8, ERR9, ERR10,
+ ERR11, ERR12, ERR13, ERR14, ERR15, ERR16, ERR17, ERR18, ERR19, ERR20,
+ ERR21, ERR22, ERR23, ERR24, ERR25, ERR26, ERR27, ERR28, ERR29, ERR30,
+ ERR31, ERR32, ERR33, ERR34, ERR35, ERR36, ERR37, ERR38, ERR39, ERR40,
+ ERR41, ERR42, ERR43, ERR44, ERR45, ERR46, ERR47, ERR48, ERR49, ERR50,
+ ERR51, ERR52, ERR53, ERR54, ERR55, ERR56, ERR57, ERR58, ERR59, ERR60,
+ ERR61, ERR62, ERR63, ERR64, ERR65, ERR66, ERR67, ERR68, ERR69, ERR70,
+ ERR71, ERR72, ERR73, ERR74, ERR75, ERR76, ERR77, ERR78, ERR79, ERR80,
+ ERR81, ERR82, ERR83, ERR84, ERR85, ERR86, ERR87, ERR88, ERR89, ERR90,
+ ERR91, ERR92, ERR93, ERR94 };
+
+/* This is a table of start-of-pattern options such as (*UTF) and settings such
+as (*LIMIT_MATCH=nnnn) and (*CRLF). For completeness and backward
+compatibility, (*UTFn) is supported in the relevant libraries, but (*UTF) is
+generic and always supported. */
+
+enum { PSO_OPT, /* Value is an option bit */
+ PSO_FLG, /* Value is a flag bit */
+ PSO_NL, /* Value is a newline type */
+ PSO_BSR, /* Value is a \R type */
+ PSO_LIMH, /* Read integer value for heap limit */
+ PSO_LIMM, /* Read integer value for match limit */
+ PSO_LIMD }; /* Read integer value for depth limit */
+
+typedef struct pso {
+ const uint8_t *name;
+ uint16_t length;
+ uint16_t type;
+ uint32_t value;
+} pso;
+
+/* NB: STRING_UTFn_RIGHTPAR contains the length as well */
+
+static pso pso_list[] = {
+ { (uint8_t *)STRING_UTFn_RIGHTPAR, PSO_OPT, PCRE2_UTF },
+ { (uint8_t *)STRING_UTF_RIGHTPAR, 4, PSO_OPT, PCRE2_UTF },
+ { (uint8_t *)STRING_UCP_RIGHTPAR, 4, PSO_OPT, PCRE2_UCP },
+ { (uint8_t *)STRING_NOTEMPTY_RIGHTPAR, 9, PSO_FLG, PCRE2_NOTEMPTY_SET },
+ { (uint8_t *)STRING_NOTEMPTY_ATSTART_RIGHTPAR, 17, PSO_FLG, PCRE2_NE_ATST_SET },
+ { (uint8_t *)STRING_NO_AUTO_POSSESS_RIGHTPAR, 16, PSO_OPT, PCRE2_NO_AUTO_POSSESS },
+ { (uint8_t *)STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR, 18, PSO_OPT, PCRE2_NO_DOTSTAR_ANCHOR },
+ { (uint8_t *)STRING_NO_JIT_RIGHTPAR, 7, PSO_FLG, PCRE2_NOJIT },
+ { (uint8_t *)STRING_NO_START_OPT_RIGHTPAR, 13, PSO_OPT, PCRE2_NO_START_OPTIMIZE },
+ { (uint8_t *)STRING_LIMIT_HEAP_EQ, 11, PSO_LIMH, 0 },
+ { (uint8_t *)STRING_LIMIT_MATCH_EQ, 12, PSO_LIMM, 0 },
+ { (uint8_t *)STRING_LIMIT_DEPTH_EQ, 12, PSO_LIMD, 0 },
+ { (uint8_t *)STRING_LIMIT_RECURSION_EQ, 16, PSO_LIMD, 0 },
+ { (uint8_t *)STRING_CR_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_CR },
+ { (uint8_t *)STRING_LF_RIGHTPAR, 3, PSO_NL, PCRE2_NEWLINE_LF },
+ { (uint8_t *)STRING_CRLF_RIGHTPAR, 5, PSO_NL, PCRE2_NEWLINE_CRLF },
+ { (uint8_t *)STRING_ANY_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_ANY },
+ { (uint8_t *)STRING_NUL_RIGHTPAR, 4, PSO_NL, PCRE2_NEWLINE_NUL },
+ { (uint8_t *)STRING_ANYCRLF_RIGHTPAR, 8, PSO_NL, PCRE2_NEWLINE_ANYCRLF },
+ { (uint8_t *)STRING_BSR_ANYCRLF_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_ANYCRLF },
+ { (uint8_t *)STRING_BSR_UNICODE_RIGHTPAR, 12, PSO_BSR, PCRE2_BSR_UNICODE }
+};
+
+/* This table is used when converting repeating opcodes into possessified
+versions as a result of an explicit possessive quantifier such as ++. A zero
+value means there is no possessified version - in those cases the item in
+question must be wrapped in ONCE brackets. The table is truncated at OP_CALLOUT
+because all relevant opcodes are less than that. */
+
+static const uint8_t opcode_possessify[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 31 */
+
+ 0, /* NOTI */
+ OP_POSSTAR, 0, /* STAR, MINSTAR */
+ OP_POSPLUS, 0, /* PLUS, MINPLUS */
+ OP_POSQUERY, 0, /* QUERY, MINQUERY */
+ OP_POSUPTO, 0, /* UPTO, MINUPTO */
+ 0, /* EXACT */
+ 0, 0, 0, 0, /* POS{STAR,PLUS,QUERY,UPTO} */
+
+ OP_POSSTARI, 0, /* STARI, MINSTARI */
+ OP_POSPLUSI, 0, /* PLUSI, MINPLUSI */
+ OP_POSQUERYI, 0, /* QUERYI, MINQUERYI */
+ OP_POSUPTOI, 0, /* UPTOI, MINUPTOI */
+ 0, /* EXACTI */
+ 0, 0, 0, 0, /* POS{STARI,PLUSI,QUERYI,UPTOI} */
+
+ OP_NOTPOSSTAR, 0, /* NOTSTAR, NOTMINSTAR */
+ OP_NOTPOSPLUS, 0, /* NOTPLUS, NOTMINPLUS */
+ OP_NOTPOSQUERY, 0, /* NOTQUERY, NOTMINQUERY */
+ OP_NOTPOSUPTO, 0, /* NOTUPTO, NOTMINUPTO */
+ 0, /* NOTEXACT */
+ 0, 0, 0, 0, /* NOTPOS{STAR,PLUS,QUERY,UPTO} */
+
+ OP_NOTPOSSTARI, 0, /* NOTSTARI, NOTMINSTARI */
+ OP_NOTPOSPLUSI, 0, /* NOTPLUSI, NOTMINPLUSI */
+ OP_NOTPOSQUERYI, 0, /* NOTQUERYI, NOTMINQUERYI */
+ OP_NOTPOSUPTOI, 0, /* NOTUPTOI, NOTMINUPTOI */
+ 0, /* NOTEXACTI */
+ 0, 0, 0, 0, /* NOTPOS{STARI,PLUSI,QUERYI,UPTOI} */
+
+ OP_TYPEPOSSTAR, 0, /* TYPESTAR, TYPEMINSTAR */
+ OP_TYPEPOSPLUS, 0, /* TYPEPLUS, TYPEMINPLUS */
+ OP_TYPEPOSQUERY, 0, /* TYPEQUERY, TYPEMINQUERY */
+ OP_TYPEPOSUPTO, 0, /* TYPEUPTO, TYPEMINUPTO */
+ 0, /* TYPEEXACT */
+ 0, 0, 0, 0, /* TYPEPOS{STAR,PLUS,QUERY,UPTO} */
+
+ OP_CRPOSSTAR, 0, /* CRSTAR, CRMINSTAR */
+ OP_CRPOSPLUS, 0, /* CRPLUS, CRMINPLUS */
+ OP_CRPOSQUERY, 0, /* CRQUERY, CRMINQUERY */
+ OP_CRPOSRANGE, 0, /* CRRANGE, CRMINRANGE */
+ 0, 0, 0, 0, /* CRPOS{STAR,PLUS,QUERY,RANGE} */
+
+ 0, 0, 0, /* CLASS, NCLASS, XCLASS */
+ 0, 0, /* REF, REFI */
+ 0, 0, /* DNREF, DNREFI */
+ 0, 0 /* RECURSE, CALLOUT */
+};
+
+
+#ifdef DEBUG_SHOW_PARSED
+/*************************************************
+* Show the parsed pattern for debugging *
+*************************************************/
+
+/* For debugging the pre-scan, this code, which outputs the parsed data vector,
+can be enabled. */
+
+static void show_parsed(compile_block *cb)
+{
+uint32_t *pptr = cb->parsed_pattern;
+
+for (;;)
+ {
+ int max, min;
+ PCRE2_SIZE offset;
+ uint32_t i;
+ uint32_t length;
+ uint32_t meta_arg = META_DATA(*pptr);
+
+ fprintf(stderr, "+++ %02d %.8x ", (int)(pptr - cb->parsed_pattern), *pptr);
+
+ if (*pptr < META_END)
+ {
+ if (*pptr > 32 && *pptr < 128) fprintf(stderr, "%c", *pptr);
+ pptr++;
+ }
+
+ else switch (META_CODE(*pptr++))
+ {
+ default:
+ fprintf(stderr, "**** OOPS - unknown META value - giving up ****\n");
+ return;
+
+ case META_END:
+ fprintf(stderr, "META_END\n");
+ return;
+
+ case META_CAPTURE:
+ fprintf(stderr, "META_CAPTURE %d", meta_arg);
+ break;
+
+ case META_RECURSE:
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "META_RECURSE %d %zd", meta_arg, offset);
+ break;
+
+ case META_BACKREF:
+ if (meta_arg < 10)
+ offset = cb->small_ref_offset[meta_arg];
+ else
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "META_BACKREF %d %zd", meta_arg, offset);
+ break;
+
+ case META_ESCAPE:
+ if (meta_arg == ESC_P || meta_arg == ESC_p)
+ {
+ uint32_t ptype = *pptr >> 16;
+ uint32_t pvalue = *pptr++ & 0xffff;
+ fprintf(stderr, "META \\%c %d %d", (meta_arg == ESC_P)? 'P':'p',
+ ptype, pvalue);
+ }
+ else
+ {
+ uint32_t cc;
+ /* There's just one escape we might have here that isn't negated in the
+ escapes table. */
+ if (meta_arg == ESC_g) cc = CHAR_g;
+ else for (cc = ESCAPES_FIRST; cc <= ESCAPES_LAST; cc++)
+ {
+ if (meta_arg == (uint32_t)(-escapes[cc - ESCAPES_FIRST])) break;
+ }
+ if (cc > ESCAPES_LAST) cc = CHAR_QUESTION_MARK;
+ fprintf(stderr, "META \\%c", cc);
+ }
+ break;
+
+ case META_MINMAX:
+ min = *pptr++;
+ max = *pptr++;
+ if (max != REPEAT_UNLIMITED)
+ fprintf(stderr, "META {%d,%d}", min, max);
+ else
+ fprintf(stderr, "META {%d,}", min);
+ break;
+
+ case META_MINMAX_QUERY:
+ min = *pptr++;
+ max = *pptr++;
+ if (max != REPEAT_UNLIMITED)
+ fprintf(stderr, "META {%d,%d}?", min, max);
+ else
+ fprintf(stderr, "META {%d,}?", min);
+ break;
+
+ case META_MINMAX_PLUS:
+ min = *pptr++;
+ max = *pptr++;
+ if (max != REPEAT_UNLIMITED)
+ fprintf(stderr, "META {%d,%d}+", min, max);
+ else
+ fprintf(stderr, "META {%d,}+", min);
+ break;
+
+ case META_BIGVALUE: fprintf(stderr, "META_BIGVALUE %.8x", *pptr++); break;
+ case META_CIRCUMFLEX: fprintf(stderr, "META_CIRCUMFLEX"); break;
+ case META_COND_ASSERT: fprintf(stderr, "META_COND_ASSERT"); break;
+ case META_DOLLAR: fprintf(stderr, "META_DOLLAR"); break;
+ case META_DOT: fprintf(stderr, "META_DOT"); break;
+ case META_ASTERISK: fprintf(stderr, "META *"); break;
+ case META_ASTERISK_QUERY: fprintf(stderr, "META *?"); break;
+ case META_ASTERISK_PLUS: fprintf(stderr, "META *+"); break;
+ case META_PLUS: fprintf(stderr, "META +"); break;
+ case META_PLUS_QUERY: fprintf(stderr, "META +?"); break;
+ case META_PLUS_PLUS: fprintf(stderr, "META ++"); break;
+ case META_QUERY: fprintf(stderr, "META ?"); break;
+ case META_QUERY_QUERY: fprintf(stderr, "META ??"); break;
+ case META_QUERY_PLUS: fprintf(stderr, "META ?+"); break;
+
+ case META_ATOMIC: fprintf(stderr, "META (?>"); break;
+ case META_NOCAPTURE: fprintf(stderr, "META (?:"); break;
+ case META_LOOKAHEAD: fprintf(stderr, "META (?="); break;
+ case META_LOOKAHEADNOT: fprintf(stderr, "META (?!"); break;
+ case META_KET: fprintf(stderr, "META )"); break;
+ case META_ALT: fprintf(stderr, "META | %d", meta_arg); break;
+
+ case META_CLASS: fprintf(stderr, "META ["); break;
+ case META_CLASS_NOT: fprintf(stderr, "META [^"); break;
+ case META_CLASS_END: fprintf(stderr, "META ]"); break;
+ case META_CLASS_EMPTY: fprintf(stderr, "META []"); break;
+ case META_CLASS_EMPTY_NOT: fprintf(stderr, "META [^]"); break;
+
+ case META_RANGE_LITERAL: fprintf(stderr, "META - (literal)"); break;
+ case META_RANGE_ESCAPED: fprintf(stderr, "META - (escaped)"); break;
+
+ case META_POSIX: fprintf(stderr, "META_POSIX %d", *pptr++); break;
+ case META_POSIX_NEG: fprintf(stderr, "META_POSIX_NEG %d", *pptr++); break;
+
+ case META_ACCEPT: fprintf(stderr, "META (*ACCEPT)"); break;
+ case META_FAIL: fprintf(stderr, "META (*FAIL)"); break;
+ case META_COMMIT: fprintf(stderr, "META (*COMMIT)"); break;
+ case META_PRUNE: fprintf(stderr, "META (*PRUNE)"); break;
+ case META_SKIP: fprintf(stderr, "META (*SKIP)"); break;
+ case META_THEN: fprintf(stderr, "META (*THEN)"); break;
+
+ case META_OPTIONS: fprintf(stderr, "META_OPTIONS 0x%02x", *pptr++); break;
+
+ case META_LOOKBEHIND:
+ fprintf(stderr, "META (?<= %d offset=", meta_arg);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_LOOKBEHINDNOT:
+ fprintf(stderr, "META (?<! %d offset=", meta_arg);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_CALLOUT_NUMBER:
+ fprintf(stderr, "META (?C%d) next=%d/%d", pptr[2], pptr[0],
+ pptr[1]);
+ pptr += 3;
+ break;
+
+ case META_CALLOUT_STRING:
+ {
+ uint32_t patoffset = *pptr++; /* Offset of next pattern item */
+ uint32_t patlength = *pptr++; /* Length of next pattern item */
+ fprintf(stderr, "META (?Cstring) length=%d offset=", *pptr++);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd next=%d/%d", offset, patoffset, patlength);
+ }
+ break;
+
+ case META_RECURSE_BYNAME:
+ fprintf(stderr, "META (?(&name) length=%d offset=", *pptr++);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_BACKREF_BYNAME:
+ fprintf(stderr, "META_BACKREF_BYNAME length=%d offset=", *pptr++);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_COND_NUMBER:
+ fprintf(stderr, "META_COND_NUMBER %d offset=", pptr[SIZEOFFSET]);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ pptr++;
+ break;
+
+ case META_COND_DEFINE:
+ fprintf(stderr, "META (?(DEFINE) offset=");
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_COND_VERSION:
+ fprintf(stderr, "META (?(VERSION%s", (*pptr++ == 0)? "=" : ">=");
+ fprintf(stderr, "%d.", *pptr++);
+ fprintf(stderr, "%d)", *pptr++);
+ break;
+
+ case META_COND_NAME:
+ fprintf(stderr, "META (?(<name>) length=%d offset=", *pptr++);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_COND_RNAME:
+ fprintf(stderr, "META (?(R&name) length=%d offset=", *pptr++);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ /* This is kept as a name, because it might be. */
+
+ case META_COND_RNUMBER:
+ fprintf(stderr, "META (?(Rnumber) length=%d offset=", *pptr++);
+ GETOFFSET(offset, pptr);
+ fprintf(stderr, "%zd", offset);
+ break;
+
+ case META_MARK:
+ fprintf(stderr, "META (*MARK:");
+ goto SHOWARG;
+
+ case META_COMMIT_ARG:
+ fprintf(stderr, "META (*COMMIT:");
+ goto SHOWARG;
+
+ case META_PRUNE_ARG:
+ fprintf(stderr, "META (*PRUNE:");
+ goto SHOWARG;
+
+ case META_SKIP_ARG:
+ fprintf(stderr, "META (*SKIP:");
+ goto SHOWARG;
+
+ case META_THEN_ARG:
+ fprintf(stderr, "META (*THEN:");
+ SHOWARG:
+ length = *pptr++;
+ for (i = 0; i < length; i++)
+ {
+ uint32_t cc = *pptr++;
+ if (cc > 32 && cc < 128) fprintf(stderr, "%c", cc);
+ else fprintf(stderr, "\\x{%x}", cc);
+ }
+ fprintf(stderr, ") length=%u", length);
+ break;
+ }
+ fprintf(stderr, "\n");
+ }
+return;
+}
+#endif /* DEBUG_SHOW_PARSED */
+
+
+
+/*************************************************
+* Copy compiled code *
+*************************************************/
+
+/* Compiled JIT code cannot be copied, so the new compiled block has no
+associated JIT data. */
+
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_code_copy(const pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+pcre2_code *newcode;
+
+if (code == NULL) return NULL;
+newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
+if (newcode == NULL) return NULL;
+memcpy(newcode, code, code->blocksize);
+newcode->executable_jit = NULL;
+
+/* If the code is one that has been deserialized, increment the reference count
+in the decoded tables. */
+
+if ((code->flags & PCRE2_DEREF_TABLES) != 0)
+ {
+ ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
+ (*ref_count)++;
+ }
+
+return newcode;
+}
+
+
+
+/*************************************************
+* Copy compiled code and character tables *
+*************************************************/
+
+/* Compiled JIT code cannot be copied, so the new compiled block has no
+associated JIT data. This version of code_copy also makes a separate copy of
+the character tables. */
+
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_code_copy_with_tables(const pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+pcre2_code *newcode;
+uint8_t *newtables;
+
+if (code == NULL) return NULL;
+newcode = code->memctl.malloc(code->blocksize, code->memctl.memory_data);
+if (newcode == NULL) return NULL;
+memcpy(newcode, code, code->blocksize);
+newcode->executable_jit = NULL;
+
+newtables = code->memctl.malloc(tables_length + sizeof(PCRE2_SIZE),
+ code->memctl.memory_data);
+if (newtables == NULL)
+ {
+ code->memctl.free((void *)newcode, code->memctl.memory_data);
+ return NULL;
+ }
+memcpy(newtables, code->tables, tables_length);
+ref_count = (PCRE2_SIZE *)(newtables + tables_length);
+*ref_count = 1;
+
+newcode->tables = newtables;
+newcode->flags |= PCRE2_DEREF_TABLES;
+return newcode;
+}
+
+
+
+/*************************************************
+* Free compiled code *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_code_free(pcre2_code *code)
+{
+PCRE2_SIZE* ref_count;
+
+if (code != NULL)
+ {
+ if (code->executable_jit != NULL)
+ PRIV(jit_free)(code->executable_jit, &code->memctl);
+
+ if ((code->flags & PCRE2_DEREF_TABLES) != 0)
+ {
+ /* Decoded tables belong to the codes after deserialization, and they must
+ be freed when there are no more reference to them. The *ref_count should
+ always be > 0. */
+
+ ref_count = (PCRE2_SIZE *)(code->tables + tables_length);
+ if (*ref_count > 0)
+ {
+ (*ref_count)--;
+ if (*ref_count == 0)
+ code->memctl.free((void *)code->tables, code->memctl.memory_data);
+ }
+ }
+
+ code->memctl.free(code, code->memctl.memory_data);
+ }
+}
+
+
+
+/*************************************************
+* Read a number, possibly signed *
+*************************************************/
+
+/* This function is used to read numbers in the pattern. The initial pointer
+must be the sign or first digit of the number. When relative values (introduced
+by + or -) are allowed, they are relative group numbers, and the result must be
+greater than zero.
+
+Arguments:
+ ptrptr points to the character pointer variable
+ ptrend points to the end of the input string
+ allow_sign if < 0, sign not allowed; if >= 0, sign is relative to this
+ max_value the largest number allowed
+ max_error the error to give for an over-large number
+ intptr where to put the result
+ errcodeptr where to put an error code
+
+Returns: TRUE - a number was read
+ FALSE - errorcode == 0 => no number was found
+ errorcode != 0 => an error occurred
+*/
+
+static BOOL
+read_number(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, int32_t allow_sign,
+ uint32_t max_value, uint32_t max_error, int *intptr, int *errorcodeptr)
+{
+int sign = 0;
+uint32_t n = 0;
+PCRE2_SPTR ptr = *ptrptr;
+BOOL yield = FALSE;
+
+*errorcodeptr = 0;
+
+if (allow_sign >= 0 && ptr < ptrend)
+ {
+ if (*ptr == CHAR_PLUS)
+ {
+ sign = +1;
+ max_value -= allow_sign;
+ ptr++;
+ }
+ else if (*ptr == CHAR_MINUS)
+ {
+ sign = -1;
+ ptr++;
+ }
+ }
+
+if (ptr >= ptrend || !IS_DIGIT(*ptr)) return FALSE;
+while (ptr < ptrend && IS_DIGIT(*ptr))
+ {
+ n = n * 10 + *ptr++ - CHAR_0;
+ if (n > max_value)
+ {
+ *errorcodeptr = max_error;
+ goto EXIT;
+ }
+ }
+
+if (allow_sign >= 0 && sign != 0)
+ {
+ if (n == 0)
+ {
+ *errorcodeptr = ERR26; /* +0 and -0 are not allowed */
+ goto EXIT;
+ }
+
+ if (sign > 0) n += allow_sign;
+ else if ((int)n > allow_sign)
+ {
+ *errorcodeptr = ERR15; /* Non-existent subpattern */
+ goto EXIT;
+ }
+ else n = allow_sign + 1 - n;
+ }
+
+yield = TRUE;
+
+EXIT:
+*intptr = n;
+*ptrptr = ptr;
+return yield;
+}
+
+
+
+/*************************************************
+* Read repeat counts *
+*************************************************/
+
+/* Read an item of the form {n,m} and return the values if non-NULL pointers
+are supplied. Repeat counts must be less than 65536 (MAX_REPEAT_COUNT); a
+larger value is used for "unlimited". We have to use signed arguments for
+read_number() because it is capable of returning a signed value.
+
+Arguments:
+ ptrptr points to pointer to character after'{'
+ ptrend pointer to end of input
+ minp if not NULL, pointer to int for min
+ maxp if not NULL, pointer to int for max (-1 if no max)
+ returned as -1 if no max
+ errorcodeptr points to error code variable
+
+Returns: FALSE if not a repeat quantifier, errorcode set zero
+ FALSE on error, with errorcode set non-zero
+ TRUE on success, with pointer updated to point after '}'
+*/
+
+static BOOL
+read_repeat_counts(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *minp,
+ uint32_t *maxp, int *errorcodeptr)
+{
+PCRE2_SPTR p = *ptrptr;
+BOOL yield = FALSE;
+int32_t min = 0;
+int32_t max = REPEAT_UNLIMITED; /* This value is larger than MAX_REPEAT_COUNT */
+
+/* NB read_number() initializes the error code to zero. The only error is for a
+number that is too big. */
+
+if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &min, errorcodeptr))
+ goto EXIT;
+
+if (p >= ptrend) goto EXIT;
+
+if (*p == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ p++;
+ max = min;
+ }
+
+else
+ {
+ if (*p++ != CHAR_COMMA || p >= ptrend) goto EXIT;
+ if (*p != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (!read_number(&p, ptrend, -1, MAX_REPEAT_COUNT, ERR5, &max,
+ errorcodeptr) || p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET)
+ goto EXIT;
+ if (max < min)
+ {
+ *errorcodeptr = ERR4;
+ goto EXIT;
+ }
+ }
+ p++;
+ }
+
+yield = TRUE;
+if (minp != NULL) *minp = (uint32_t)min;
+if (maxp != NULL) *maxp = (uint32_t)max;
+
+/* Update the pattern pointer on success, or after an error, but not when
+the result is "not a repeat quantifier". */
+
+EXIT:
+if (yield || *errorcodeptr != 0) *ptrptr = p;
+return yield;
+
+
+
+}
+
+
+
+/*************************************************
+* Handle escapes *
+*************************************************/
+
+/* This function is called when a \ has been encountered. It either returns a
+positive value for a simple escape such as \d, or 0 for a data character, which
+is placed in chptr. A backreference to group n is returned as negative n. On
+entry, ptr is pointing at the character after \. On exit, it points after the
+final code unit of the escape sequence.
+
+This function is also called from pcre2_substitute() to handle escape sequences
+in replacement strings. In this case, the cb argument is NULL, and in the case
+of escapes that have further processing, only sequences that define a data
+character are recognised. The isclass argument is not relevant; the options
+argument is the final value of the compiled pattern's options.
+
+Arguments:
+ ptrptr points to the input position pointer
+ ptrend points to the end of the input
+ chptr points to a returned data character
+ errorcodeptr points to the errorcode variable (containing zero)
+ options the current options bits
+ isclass TRUE if inside a character class
+ cb compile data block
+
+Returns: zero => a data character
+ positive => a special escape sequence
+ negative => a numerical back reference
+ on error, errorcodeptr is set non-zero
+*/
+
+int
+PRIV(check_escape)(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t *chptr,
+ int *errorcodeptr, uint32_t options, BOOL isclass, compile_block *cb)
+{
+BOOL utf = (options & PCRE2_UTF) != 0;
+PCRE2_SPTR ptr = *ptrptr;
+uint32_t c, cc;
+int escape = 0;
+int i;
+
+/* If backslash is at the end of the string, it's an error. */
+
+if (ptr >= ptrend)
+ {
+ *errorcodeptr = ERR1;
+ return 0;
+ }
+
+GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */
+*errorcodeptr = 0; /* Be optimistic */
+
+/* Non-alphanumerics are literals, so we just leave the value in c. An initial
+value test saves a memory lookup for code points outside the alphanumeric
+range. Otherwise, do a table lookup. A non-zero result is something that can be
+returned immediately. Otherwise further processing is required. */
+
+if (c < ESCAPES_FIRST || c > ESCAPES_LAST) {} /* Definitely literal */
+
+else if ((i = escapes[c - ESCAPES_FIRST]) != 0)
+ {
+ if (i > 0) c = (uint32_t)i; else /* Positive is a data character */
+ {
+ escape = -i; /* Else return a special escape */
+ if (cb != NULL && (escape == ESC_P || escape == ESC_p || escape == ESC_X))
+ cb->external_flags |= PCRE2_HASBKPORX; /* Note \P, \p, or \X */
+
+ /* Perl supports \N{name} for character names and \N{U+dddd} for numerical
+ Unicode code points, as well as plain \N for "not newline". PCRE does not
+ support \N{name}. However, it does support quantification such as \N{2,3},
+ so if \N{ is not followed by U+dddd we check for a quantifier. */
+
+ if (escape == ESC_N && ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET)
+ {
+ PCRE2_SPTR p = ptr + 1;
+
+ /* \N{U+ can be handled by the \x{ code. However, this construction is
+ not valid in EBCDIC environments because it specifies a Unicode
+ character, not a codepoint in the local code. For example \N{U+0041}
+ must be "A" in all environments. Also, in Perl, \N{U+ forces Unicode
+ casing semantics for the entire pattern, so allow it only in UTF (i.e.
+ Unicode) mode. */
+
+ if (ptrend - p > 1 && *p == CHAR_U && p[1] == CHAR_PLUS)
+ {
+#ifdef EBCDIC
+ *errorcodeptr = ERR93;
+#else
+ if (utf)
+ {
+ ptr = p + 1;
+ escape = 0; /* Not a fancy escape after all */
+ goto COME_FROM_NU;
+ }
+ else *errorcodeptr = ERR93;
+#endif
+ }
+
+ /* Give an error if what follows is not a quantifier, but don't override
+ an error set by the quantifier reader (e.g. number overflow). */
+
+ else
+ {
+ if (!read_repeat_counts(&p, ptrend, NULL, NULL, errorcodeptr) &&
+ *errorcodeptr == 0)
+ *errorcodeptr = ERR37;
+ }
+ }
+ }
+ }
+
+/* Escapes that need further processing, including those that are unknown.
+When called from pcre2_substitute(), only \c, \o, and \x are recognized (and \u
+when BSUX is set). */
+
+else
+ {
+ PCRE2_SPTR oldptr;
+ BOOL overflow;
+ int s;
+
+ /* Filter calls from pcre2_substitute(). */
+
+ if (cb == NULL && c != CHAR_c && c != CHAR_o && c != CHAR_x &&
+ (c != CHAR_u || (options & PCRE2_ALT_BSUX) != 0))
+ {
+ *errorcodeptr = ERR3;
+ return 0;
+ }
+
+ switch (c)
+ {
+ /* A number of Perl escapes are not handled by PCRE. We give an explicit
+ error. */
+
+ case CHAR_F:
+ case CHAR_l:
+ case CHAR_L:
+ *errorcodeptr = ERR37;
+ break;
+
+ /* \u is unrecognized when PCRE2_ALT_BSUX is not set. When it is treated
+ specially, \u must be followed by four hex digits. Otherwise it is a
+ lowercase u letter. */
+
+ case CHAR_u:
+ if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37; else
+ {
+ uint32_t xc;
+ if (ptrend - ptr < 4) break; /* Less than 4 chars */
+ if ((cc = XDIGIT(ptr[0])) == 0xff) break; /* Not a hex digit */
+ if ((xc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */
+ cc = (cc << 4) | xc;
+ if ((xc = XDIGIT(ptr[2])) == 0xff) break; /* Not a hex digit */
+ cc = (cc << 4) | xc;
+ if ((xc = XDIGIT(ptr[3])) == 0xff) break; /* Not a hex digit */
+ c = (cc << 4) | xc;
+ ptr += 4;
+ if (utf)
+ {
+ if (c > 0x10ffffU) *errorcodeptr = ERR77;
+ else
+ if (c >= 0xd800 && c <= 0xdfff &&
+ (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0)
+ *errorcodeptr = ERR73;
+ }
+ else if (c > MAX_NON_UTF_CHAR) *errorcodeptr = ERR77;
+ }
+ break;
+
+ /* \U is unrecognized unless PCRE2_ALT_BSUX is set, in which case it is an
+ upper case letter. */
+
+ case CHAR_U:
+ if ((options & PCRE2_ALT_BSUX) == 0) *errorcodeptr = ERR37;
+ break;
+
+ /* In a character class, \g is just a literal "g". Outside a character
+ class, \g must be followed by one of a number of specific things:
+
+ (1) A number, either plain or braced. If positive, it is an absolute
+ backreference. If negative, it is a relative backreference. This is a Perl
+ 5.10 feature.
+
+ (2) Perl 5.10 also supports \g{name} as a reference to a named group. This
+ is part of Perl's movement towards a unified syntax for back references. As
+ this is synonymous with \k{name}, we fudge it up by pretending it really
+ was \k{name}.
+
+ (3) For Oniguruma compatibility we also support \g followed by a name or a
+ number either in angle brackets or in single quotes. However, these are
+ (possibly recursive) subroutine calls, _not_ backreferences. We return
+ the ESC_g code.
+
+ Summary: Return a negative number for a numerical back reference, ESC_k for
+ a named back reference, and ESC_g for a named or numbered subroutine call.
+ */
+
+ case CHAR_g:
+ if (isclass) break;
+
+ if (ptr >= ptrend)
+ {
+ *errorcodeptr = ERR57;
+ break;
+ }
+
+ if (*ptr == CHAR_LESS_THAN_SIGN || *ptr == CHAR_APOSTROPHE)
+ {
+ escape = ESC_g;
+ break;
+ }
+
+ /* If there is a brace delimiter, try to read a numerical reference. If
+ there isn't one, assume we have a name and treat it as \k. */
+
+ if (*ptr == CHAR_LEFT_CURLY_BRACKET)
+ {
+ PCRE2_SPTR p = ptr + 1;
+ if (!read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
+ errorcodeptr))
+ {
+ if (*errorcodeptr == 0) escape = ESC_k; /* No number found */
+ break;
+ }
+ if (p >= ptrend || *p != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ *errorcodeptr = ERR57;
+ break;
+ }
+ ptr = p + 1;
+ }
+
+ /* Read an undelimited number */
+
+ else
+ {
+ if (!read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &s,
+ errorcodeptr))
+ {
+ if (*errorcodeptr == 0) *errorcodeptr = ERR57; /* No number found */
+ break;
+ }
+ }
+
+ if (s <= 0)
+ {
+ *errorcodeptr = ERR15;
+ break;
+ }
+
+ escape = -s;
+ break;
+
+ /* The handling of escape sequences consisting of a string of digits
+ starting with one that is not zero is not straightforward. Perl has changed
+ over the years. Nowadays \g{} for backreferences and \o{} for octal are
+ recommended to avoid the ambiguities in the old syntax.
+
+ Outside a character class, the digits are read as a decimal number. If the
+ number is less than 10, or if there are that many previous extracting left
+ brackets, it is a back reference. Otherwise, up to three octal digits are
+ read to form an escaped character code. Thus \123 is likely to be octal 123
+ (cf \0123, which is octal 012 followed by the literal 3).
+
+ Inside a character class, \ followed by a digit is always either a literal
+ 8 or 9 or an octal number. */
+
+ case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4: case CHAR_5:
+ case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
+
+ if (!isclass)
+ {
+ oldptr = ptr;
+ ptr--; /* Back to the digit */
+ if (!read_number(&ptr, ptrend, -1, INT_MAX/10 - 1, ERR61, &s,
+ errorcodeptr))
+ break;
+
+ /* \1 to \9 are always back references. \8x and \9x are too; \1x to \7x
+ are octal escapes if there are not that many previous captures. */
+
+ if (s < 10 || oldptr[-1] >= CHAR_8 || s <= (int)cb->bracount)
+ {
+ if (s > (int)MAX_GROUP_NUMBER) *errorcodeptr = ERR61;
+ else escape = -s; /* Indicates a back reference */
+ break;
+ }
+ ptr = oldptr; /* Put the pointer back and fall through */
+ }
+
+ /* Handle a digit following \ when the number is not a back reference, or
+ we are within a character class. If the first digit is 8 or 9, Perl used to
+ generate a binary zero and then treat the digit as a following literal. At
+ least by Perl 5.18 this changed so as not to insert the binary zero. */
+
+ if (c >= CHAR_8) break;
+
+ /* Fall through */
+
+ /* \0 always starts an octal number, but we may drop through to here with a
+ larger first octal digit. The original code used just to take the least
+ significant 8 bits of octal numbers (I think this is what early Perls used
+ to do). Nowadays we allow for larger numbers in UTF-8 mode and 16-bit mode,
+ but no more than 3 octal digits. */
+
+ case CHAR_0:
+ c -= CHAR_0;
+ while(i++ < 2 && ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
+ c = c * 8 + *ptr++ - CHAR_0;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (!utf && c > 0xff) *errorcodeptr = ERR51;
+#endif
+ break;
+
+ /* \o is a relatively new Perl feature, supporting a more general way of
+ specifying character codes in octal. The only supported form is \o{ddd}. */
+
+ case CHAR_o:
+ if (ptr >= ptrend || *ptr++ != CHAR_LEFT_CURLY_BRACKET)
+ {
+ ptr--;
+ *errorcodeptr = ERR55;
+ }
+ else if (ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+ *errorcodeptr = ERR78;
+ else
+ {
+ c = 0;
+ overflow = FALSE;
+ while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7)
+ {
+ cc = *ptr++;
+ if (c == 0 && cc == CHAR_0) continue; /* Leading zeroes */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c >= 0x20000000l) { overflow = TRUE; break; }
+#endif
+ c = (c << 3) + (cc - CHAR_0);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (c > (utf ? 0x10ffffU : 0xffU)) { overflow = TRUE; break; }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ if (c > (utf ? 0x10ffffU : 0xffffU)) { overflow = TRUE; break; }
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ if (utf && c > 0x10ffffU) { overflow = TRUE; break; }
+#endif
+ }
+ if (overflow)
+ {
+ while (ptr < ptrend && *ptr >= CHAR_0 && *ptr <= CHAR_7) ptr++;
+ *errorcodeptr = ERR34;
+ }
+ else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (utf && c >= 0xd800 && c <= 0xdfff && (cb == NULL ||
+ (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0))
+ {
+ ptr--;
+ *errorcodeptr = ERR73;
+ }
+ }
+ else
+ {
+ ptr--;
+ *errorcodeptr = ERR64;
+ }
+ }
+ break;
+
+ /* \x is complicated. When PCRE2_ALT_BSUX is set, \x must be followed by
+ two hexadecimal digits. Otherwise it is a lowercase x letter. */
+
+ case CHAR_x:
+ if ((options & PCRE2_ALT_BSUX) != 0)
+ {
+ uint32_t xc;
+ if (ptrend - ptr < 2) break; /* Less than 2 characters */
+ if ((cc = XDIGIT(ptr[0])) == 0xff) break; /* Not a hex digit */
+ if ((xc = XDIGIT(ptr[1])) == 0xff) break; /* Not a hex digit */
+ c = (cc << 4) | xc;
+ ptr += 2;
+ } /* End PCRE2_ALT_BSUX handling */
+
+ /* Handle \x in Perl's style. \x{ddd} is a character number which can be
+ greater than 0xff in UTF-8 or non-8bit mode, but only if the ddd are hex
+ digits. If not, { used to be treated as a data character. However, Perl
+ seems to read hex digits up to the first non-such, and ignore the rest, so
+ that, for example \x{zz} matches a binary zero. This seems crazy, so PCRE
+ now gives an error. */
+
+ else
+ {
+ if (ptr < ptrend && *ptr == CHAR_LEFT_CURLY_BRACKET)
+ {
+#ifndef EBCDIC
+ COME_FROM_NU:
+#endif
+ if (++ptr >= ptrend || *ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ *errorcodeptr = ERR78;
+ break;
+ }
+ c = 0;
+ overflow = FALSE;
+
+ while (ptr < ptrend && (cc = XDIGIT(*ptr)) != 0xff)
+ {
+ ptr++;
+ if (c == 0 && cc == 0) continue; /* Leading zeroes */
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (c >= 0x10000000l) { overflow = TRUE; break; }
+#endif
+ c = (c << 4) | cc;
+ if ((utf && c > 0x10ffffU) || (!utf && c > MAX_NON_UTF_CHAR))
+ {
+ overflow = TRUE;
+ break;
+ }
+ }
+
+ if (overflow)
+ {
+ while (ptr < ptrend && XDIGIT(*ptr) != 0xff) ptr++;
+ *errorcodeptr = ERR34;
+ }
+ else if (ptr < ptrend && *ptr++ == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (utf && c >= 0xd800 && c <= 0xdfff && (cb == NULL ||
+ (cb->cx->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) == 0))
+ {
+ ptr--;
+ *errorcodeptr = ERR73;
+ }
+ }
+
+ /* If the sequence of hex digits does not end with '}', give an error.
+ We used just to recognize this construct and fall through to the normal
+ \x handling, but nowadays Perl gives an error, which seems much more
+ sensible, so we do too. */
+
+ else
+ {
+ ptr--;
+ *errorcodeptr = ERR67;
+ }
+ } /* End of \x{} processing */
+
+ /* Read a up to two hex digits after \x */
+
+ else
+ {
+ c = 0;
+ if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break; /* Not a hex digit */
+ ptr++;
+ c = cc;
+ if (ptr >= ptrend || (cc = XDIGIT(*ptr)) == 0xff) break; /* Not a hex digit */
+ ptr++;
+ c = (c << 4) | cc;
+ } /* End of \xdd handling */
+ } /* End of Perl-style \x handling */
+ break;
+
+ /* The handling of \c is different in ASCII and EBCDIC environments. In an
+ ASCII (or Unicode) environment, an error is given if the character
+ following \c is not a printable ASCII character. Otherwise, the following
+ character is upper-cased if it is a letter, and after that the 0x40 bit is
+ flipped. The result is the value of the escape.
+
+ In an EBCDIC environment the handling of \c is compatible with the
+ specification in the perlebcdic document. The following character must be
+ a letter or one of small number of special characters. These provide a
+ means of defining the character values 0-31.
+
+ For testing the EBCDIC handling of \c in an ASCII environment, recognize
+ the EBCDIC value of 'c' explicitly. */
+
+#if defined EBCDIC && 'a' != 0x81
+ case 0x83:
+#else
+ case CHAR_c:
+#endif
+ if (ptr >= ptrend)
+ {
+ *errorcodeptr = ERR2;
+ break;
+ }
+ c = *ptr;
+ if (c >= CHAR_a && c <= CHAR_z) c = UPPER_CASE(c);
+
+ /* Handle \c in an ASCII/Unicode environment. */
+
+#ifndef EBCDIC /* ASCII/UTF-8 coding */
+ if (c < 32 || c > 126) /* Excludes all non-printable ASCII */
+ {
+ *errorcodeptr = ERR68;
+ break;
+ }
+ c ^= 0x40;
+
+ /* Handle \c in an EBCDIC environment. The special case \c? is converted to
+ 255 (0xff) or 95 (0x5f) if other character suggest we are using th POSIX-BC
+ encoding. (This is the way Perl indicates that it handles \c?.) The other
+ valid sequences correspond to a list of specific characters. */
+
+#else
+ if (c == CHAR_QUESTION_MARK)
+ c = ('\\' == 188 && '`' == 74)? 0x5f : 0xff;
+ else
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (c == ebcdic_escape_c[i]) break;
+ }
+ if (i < 32) c = i; else *errorcodeptr = ERR68;
+ }
+#endif /* EBCDIC */
+
+ ptr++;
+ break;
+
+ /* Any other alphanumeric following \ is an error. Perl gives an error only
+ if in warning mode, but PCRE doesn't have a warning mode. */
+
+ default:
+ *errorcodeptr = ERR3;
+ *ptrptr = ptr - 1; /* Point to the character at fault */
+ return 0;
+ }
+ }
+
+/* Set the pointer to the next character before returning. */
+
+*ptrptr = ptr;
+*chptr = c;
+return escape;
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+* Handle \P and \p *
+*************************************************/
+
+/* This function is called after \P or \p has been encountered, provided that
+PCRE2 is compiled with support for UTF and Unicode properties. On entry, the
+contents of ptrptr are pointing after the P or p. On exit, it is left pointing
+after the final code unit of the escape sequence.
+
+Arguments:
+ ptrptr the pattern position pointer
+ negptr a boolean that is set TRUE for negation else FALSE
+ ptypeptr an unsigned int that is set to the type value
+ pdataptr an unsigned int that is set to the detailed property value
+ errorcodeptr the error code variable
+ cb the compile data
+
+Returns: TRUE if the type value was found, or FALSE for an invalid type
+*/
+
+static BOOL
+get_ucp(PCRE2_SPTR *ptrptr, BOOL *negptr, uint16_t *ptypeptr,
+ uint16_t *pdataptr, int *errorcodeptr, compile_block *cb)
+{
+PCRE2_UCHAR c;
+PCRE2_SIZE i, bot, top;
+PCRE2_SPTR ptr = *ptrptr;
+PCRE2_UCHAR name[32];
+
+if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+c = *ptr++;
+*negptr = FALSE;
+
+/* \P or \p can be followed by a name in {}, optionally preceded by ^ for
+negation. */
+
+if (c == CHAR_LEFT_CURLY_BRACKET)
+ {
+ if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+ if (*ptr == CHAR_CIRCUMFLEX_ACCENT)
+ {
+ *negptr = TRUE;
+ ptr++;
+ }
+ for (i = 0; i < (int)(sizeof(name) / sizeof(PCRE2_UCHAR)) - 1; i++)
+ {
+ if (ptr >= cb->end_pattern) goto ERROR_RETURN;
+ c = *ptr++;
+ if (c == CHAR_NUL) goto ERROR_RETURN;
+ if (c == CHAR_RIGHT_CURLY_BRACKET) break;
+ name[i] = c;
+ }
+ if (c != CHAR_RIGHT_CURLY_BRACKET) goto ERROR_RETURN;
+ name[i] = 0;
+ }
+
+/* Otherwise there is just one following character, which must be an ASCII
+letter. */
+
+else if (MAX_255(c) && (cb->ctypes[c] & ctype_letter) != 0)
+ {
+ name[0] = c;
+ name[1] = 0;
+ }
+else goto ERROR_RETURN;
+
+*ptrptr = ptr;
+
+/* Search for a recognized property name using binary chop. */
+
+bot = 0;
+top = PRIV(utt_size);
+
+while (bot < top)
+ {
+ int r;
+ i = (bot + top) >> 1;
+ r = PRIV(strcmp_c8)(name, PRIV(utt_names) + PRIV(utt)[i].name_offset);
+ if (r == 0)
+ {
+ *ptypeptr = PRIV(utt)[i].type;
+ *pdataptr = PRIV(utt)[i].value;
+ return TRUE;
+ }
+ if (r > 0) bot = i + 1; else top = i;
+ }
+*errorcodeptr = ERR47; /* Unrecognized name */
+return FALSE;
+
+ERROR_RETURN: /* Malformed \P or \p */
+*errorcodeptr = ERR46;
+*ptrptr = ptr;
+return FALSE;
+}
+#endif
+
+
+
+/*************************************************
+* Check for POSIX class syntax *
+*************************************************/
+
+/* This function is called when the sequence "[:" or "[." or "[=" is
+encountered in a character class. It checks whether this is followed by a
+sequence of characters terminated by a matching ":]" or ".]" or "=]". If we
+reach an unescaped ']' without the special preceding character, return FALSE.
+
+Originally, this function only recognized a sequence of letters between the
+terminators, but it seems that Perl recognizes any sequence of characters,
+though of course unknown POSIX names are subsequently rejected. Perl gives an
+"Unknown POSIX class" error for [:f\oo:] for example, where previously PCRE
+didn't consider this to be a POSIX class. Likewise for [:1234:].
+
+The problem in trying to be exactly like Perl is in the handling of escapes. We
+have to be sure that [abc[:x\]pqr] is *not* treated as containing a POSIX
+class, but [abc[:x\]pqr:]] is (so that an error can be generated). The code
+below handles the special cases \\ and \], but does not try to do any other
+escape processing. This makes it different from Perl for cases such as
+[:l\ower:] where Perl recognizes it as the POSIX class "lower" but PCRE does
+not recognize "l\ower". This is a lesser evil than not diagnosing bad classes
+when Perl does, I think.
+
+A user pointed out that PCRE was rejecting [:a[:digit:]] whereas Perl was not.
+It seems that the appearance of a nested POSIX class supersedes an apparent
+external class. For example, [:a[:digit:]b:] matches "a", "b", ":", or
+a digit. This is handled by returning FALSE if the start of a new group with
+the same terminator is encountered, since the next closing sequence must close
+the nested group, not the outer one.
+
+In Perl, unescaped square brackets may also appear as part of class names. For
+example, [:a[:abc]b:] gives unknown POSIX class "[:abc]b:]". However, for
+[:a[:abc]b][b:] it gives unknown POSIX class "[:abc]b][b:]", which does not
+seem right at all. PCRE does not allow closing square brackets in POSIX class
+names.
+
+Arguments:
+ ptr pointer to the character after the initial [ (colon, dot, equals)
+ ptrend pointer to the end of the pattern
+ endptr where to return a pointer to the terminating ':', '.', or '='
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+check_posix_syntax(PCRE2_SPTR ptr, PCRE2_SPTR ptrend, PCRE2_SPTR *endptr)
+{
+PCRE2_UCHAR terminator; /* Don't combine these lines; the Solaris cc */
+terminator = *ptr++; /* compiler warns about "non-constant" initializer. */
+
+for (; ptrend - ptr >= 2; ptr++)
+ {
+ if (*ptr == CHAR_BACKSLASH &&
+ (ptr[1] == CHAR_RIGHT_SQUARE_BRACKET || ptr[1] == CHAR_BACKSLASH))
+ ptr++;
+
+ else if ((*ptr == CHAR_LEFT_SQUARE_BRACKET && ptr[1] == terminator) ||
+ *ptr == CHAR_RIGHT_SQUARE_BRACKET) return FALSE;
+
+ else if (*ptr == terminator && ptr[1] == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ *endptr = ptr;
+ return TRUE;
+ }
+ }
+
+return FALSE;
+}
+
+
+
+/*************************************************
+* Check POSIX class name *
+*************************************************/
+
+/* This function is called to check the name given in a POSIX-style class entry
+such as [:alnum:].
+
+Arguments:
+ ptr points to the first letter
+ len the length of the name
+
+Returns: a value representing the name, or -1 if unknown
+*/
+
+static int
+check_posix_name(PCRE2_SPTR ptr, int len)
+{
+const char *pn = posix_names;
+int yield = 0;
+while (posix_name_lengths[yield] != 0)
+ {
+ if (len == posix_name_lengths[yield] &&
+ PRIV(strncmp_c8)(ptr, pn, (unsigned int)len) == 0) return yield;
+ pn += posix_name_lengths[yield] + 1;
+ yield++;
+ }
+return -1;
+}
+
+
+
+/*************************************************
+* Read a subpattern or VERB name *
+*************************************************/
+
+/* This function is called from parse_regex() below whenever it needs to read
+the name of a subpattern or a (*VERB). The initial pointer must be to the
+character before the name. If that character is '*' we are reading a verb name.
+The pointer is updated to point after the name, for a VERB, or after tha name's
+terminator for a subpattern name. Returning both the offset and the name
+pointer is redundant information, but some callers use one and some the other,
+so it is simplest just to return both.
+
+Arguments:
+ ptrptr points to the character pointer variable
+ ptrend points to the end of the input string
+ terminator the terminator of a subpattern name must be this
+ offsetptr where to put the offset from the start of the pattern
+ nameptr where to put a pointer to the name in the input
+ namelenptr where to put the length of the name
+ errcodeptr where to put an error code
+ cb pointer to the compile data block
+
+Returns: TRUE if a name was read
+ FALSE otherwise, with error code set
+*/
+
+static BOOL
+read_name(PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend, uint32_t terminator,
+ PCRE2_SIZE *offsetptr, PCRE2_SPTR *nameptr, uint32_t *namelenptr,
+ int *errorcodeptr, compile_block *cb)
+{
+PCRE2_SPTR ptr = *ptrptr;
+BOOL is_verb = (*ptr == CHAR_ASTERISK);
+uint32_t namelen = 0;
+uint32_t ctype = is_verb? ctype_letter : ctype_word;
+
+if (++ptr >= ptrend)
+ {
+ *errorcodeptr = is_verb? ERR60: /* Verb not recognized or malformed */
+ ERR62; /* Subpattern name expected */
+ goto FAILED;
+ }
+
+*nameptr = ptr;
+*offsetptr = (PCRE2_SIZE)(ptr - cb->start_pattern);
+
+if (IS_DIGIT(*ptr))
+ {
+ *errorcodeptr = ERR44; /* Group name must not start with digit */
+ goto FAILED;
+ }
+
+while (ptr < ptrend && MAX_255(*ptr) && (cb->ctypes[*ptr] & ctype) != 0)
+ {
+ ptr++;
+ namelen++;
+ if (namelen > MAX_NAME_SIZE)
+ {
+ *errorcodeptr = ERR48;
+ goto FAILED;
+ }
+ }
+
+/* Subpattern names must not be empty, and their terminator is checked here.
+(What follows a verb name is checked separately.) */
+
+if (!is_verb)
+ {
+ if (namelen == 0)
+ {
+ *errorcodeptr = ERR62; /* Subpattern name expected */
+ goto FAILED;
+ }
+ if (ptr >= ptrend || *ptr != (PCRE2_UCHAR)terminator)
+ {
+ *errorcodeptr = ERR42;
+ goto FAILED;
+ }
+ ptr++;
+ }
+
+*namelenptr = namelen;
+*ptrptr = ptr;
+return TRUE;
+
+FAILED:
+*ptrptr = ptr;
+return FALSE;
+}
+
+
+
+/*************************************************
+* Manage callouts at start of cycle *
+*************************************************/
+
+/* At the start of a new item in parse_regex() we are able to record the
+details of the previous item in a prior callout, and also to set up an
+automatic callout if enabled. Avoid having two adjacent automatic callouts,
+which would otherwise happen for items such as \Q that contribute nothing to
+the parsed pattern.
+
+Arguments:
+ ptr current pattern pointer
+ pcalloutptr points to a pointer to previous callout, or NULL
+ auto_callout TRUE if auto_callouts are enabled
+ parsed_pattern the parsed pattern pointer
+ cb compile block
+
+Returns: possibly updated parsed_pattern pointer.
+*/
+
+static uint32_t *
+manage_callouts(PCRE2_SPTR ptr, uint32_t **pcalloutptr, BOOL auto_callout,
+ uint32_t *parsed_pattern, compile_block *cb)
+{
+uint32_t *previous_callout = *pcalloutptr;
+
+if (previous_callout != NULL) previous_callout[2] = (uint32_t)(ptr -
+ cb->start_pattern - (PCRE2_SIZE)previous_callout[1]);
+
+if (!auto_callout) previous_callout = NULL; else
+ {
+ if (previous_callout == NULL ||
+ previous_callout != parsed_pattern - 4 ||
+ previous_callout[3] != 255)
+ {
+ previous_callout = parsed_pattern; /* Set up new automatic callout */
+ parsed_pattern += 4;
+ previous_callout[0] = META_CALLOUT_NUMBER;
+ previous_callout[2] = 0;
+ previous_callout[3] = 255;
+ }
+ previous_callout[1] = (uint32_t)(ptr - cb->start_pattern);
+ }
+
+*pcalloutptr = previous_callout;
+return parsed_pattern;
+}
+
+
+
+/*************************************************
+* Parse regex and identify named groups *
+*************************************************/
+
+/* This function is called first of all. It scans the pattern and does two
+things: (1) It identifies capturing groups and makes a table of named capturing
+groups so that information about them is fully available to both the compiling
+scans. (2) It writes a parsed version of the pattern with comments omitted and
+escapes processed into the parsed_pattern vector.
+
+Arguments:
+ ptr points to the start of the pattern
+ options compiling dynamic options (may change during the scan)
+ has_lookbehind points to a boolean, set TRUE if a lookbehind is found
+ cb pointer to the compile data block
+
+Returns: zero on success or a non-zero error code, with the
+ error offset placed in the cb field
+*/
+
+/* A structure and some flags for dealing with nested groups. */
+
+typedef struct nest_save {
+ uint16_t nest_depth;
+ uint16_t reset_group;
+ uint16_t max_group;
+ uint16_t flags;
+ uint32_t options;
+} nest_save;
+
+#define NSF_RESET 0x0001u
+#define NSF_CONDASSERT 0x0002u
+
+/* Options that are changeable within the pattern must be tracked during
+parsing. Some (e.g. PCRE2_EXTENDED) are implemented entirely during parsing,
+but all must be tracked so that META_OPTIONS items set the correct values for
+the main compiling phase. */
+
+#define PARSE_TRACKED_OPTIONS (PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_DUPNAMES| \
+ PCRE2_EXTENDED|PCRE2_EXTENDED_MORE|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE| \
+ PCRE2_UNGREEDY)
+
+/* States used for analyzing ranges in character classes. The two OK values
+must be last. */
+
+enum { RANGE_NO, RANGE_STARTED, RANGE_OK_ESCAPED, RANGE_OK_LITERAL };
+
+/* Only in 32-bit mode can there be literals > META_END. A macros encapsulates
+the storing of literal values in the parsed pattern. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define PARSED_LITERAL(c, p) \
+ { \
+ if (c >= META_END) *p++ = META_BIGVALUE; \
+ *p++ = c; \
+ okquantifier = TRUE; \
+ }
+#else
+#define PARSED_LITERAL(c, p) *p++ = c; okquantifier = TRUE;
+#endif
+
+/* Here's the actual function. */
+
+static int parse_regex(PCRE2_SPTR ptr, uint32_t options, BOOL *has_lookbehind,
+ compile_block *cb)
+{
+uint32_t c;
+uint32_t delimiter;
+uint32_t namelen;
+uint32_t class_range_state;
+uint32_t *verblengthptr = NULL; /* Value avoids compiler warning */
+uint32_t *previous_callout = NULL;
+uint32_t *parsed_pattern = cb->parsed_pattern;
+uint32_t *parsed_pattern_end = cb->parsed_pattern_end;
+uint32_t meta_quantifier = 0;
+uint32_t add_after_mark = 0;
+uint16_t nest_depth = 0;
+int after_manual_callout = 0;
+int expect_cond_assert = 0;
+int errorcode = 0;
+int escape;
+int i;
+BOOL inescq = FALSE;
+BOOL inverbname = FALSE;
+BOOL utf = (options & PCRE2_UTF) != 0;
+BOOL auto_callout = (options & PCRE2_AUTO_CALLOUT) != 0;
+BOOL isdupname;
+BOOL negate_class;
+BOOL okquantifier = FALSE;
+PCRE2_SPTR thisptr;
+PCRE2_SPTR name;
+PCRE2_SPTR ptrend = cb->end_pattern;
+PCRE2_SPTR verbnamestart = NULL; /* Value avoids compiler warning */
+named_group *ng;
+nest_save *top_nest, *end_nests;
+
+/* Insert leading items for word and line matching (features provided for the
+benefit of pcre2grep). */
+
+if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_LINE) != 0)
+ {
+ *parsed_pattern++ = META_CIRCUMFLEX;
+ *parsed_pattern++ = META_NOCAPTURE;
+ }
+else if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_WORD) != 0)
+ {
+ *parsed_pattern++ = META_ESCAPE + ESC_b;
+ *parsed_pattern++ = META_NOCAPTURE;
+ }
+
+/* If the pattern is actually a literal string, process it separately to avoid
+cluttering up the main loop. */
+
+if ((options & PCRE2_LITERAL) != 0)
+ {
+ while (ptr < ptrend)
+ {
+ if (parsed_pattern >= parsed_pattern_end)
+ {
+ errorcode = ERR63; /* Internal error (parsed pattern overflow) */
+ goto FAILED;
+ }
+ thisptr = ptr;
+ GETCHARINCTEST(c, ptr);
+ if (auto_callout)
+ parsed_pattern = manage_callouts(thisptr, &previous_callout,
+ auto_callout, parsed_pattern, cb);
+ PARSED_LITERAL(c, parsed_pattern);
+ }
+ goto PARSED_END;
+ }
+
+/* Process a real regex which may contain meta-characters. */
+
+top_nest = NULL;
+end_nests = (nest_save *)(cb->start_workspace + cb->workspace_size);
+
+/* The size of the nest_save structure might not be a factor of the size of the
+workspace. Therefore we must round down end_nests so as to correctly avoid
+creating a nest_save that spans the end of the workspace. */
+
+end_nests = (nest_save *)((char *)end_nests -
+ ((cb->workspace_size * sizeof(PCRE2_UCHAR)) % sizeof(nest_save)));
+
+/* PCRE2_EXTENDED_MORE implies PCRE2_EXTENDED */
+
+if ((options & PCRE2_EXTENDED_MORE) != 0) options |= PCRE2_EXTENDED;
+
+/* Now scan the pattern */
+
+while (ptr < ptrend)
+ {
+ int prev_expect_cond_assert;
+ uint32_t min_repeat, max_repeat;
+ uint32_t set, unset, *optset;
+ uint32_t terminator;
+ uint32_t prev_meta_quantifier;
+ BOOL prev_okquantifier;
+ PCRE2_SPTR tempptr;
+ PCRE2_SIZE offset;
+
+ if (parsed_pattern >= parsed_pattern_end)
+ {
+ errorcode = ERR63; /* Internal error (parsed pattern overflow) */
+ goto FAILED;
+ }
+
+ if (nest_depth > cb->cx->parens_nest_limit)
+ {
+ errorcode = ERR19;
+ goto FAILED; /* Parentheses too deeply nested */
+ }
+
+ /* Get next input character, save its position for callout handling. */
+
+ thisptr = ptr;
+ GETCHARINCTEST(c, ptr);
+
+ /* Copy quoted literals until \E, allowing for the possibility of automatic
+ callouts, except when processing a (*VERB) "name". */
+
+ if (inescq)
+ {
+ if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E)
+ {
+ inescq = FALSE;
+ ptr++; /* Skip E */
+ }
+ else
+ {
+ if (expect_cond_assert > 0) /* A literal is not allowed if we are */
+ { /* expecting a conditional assertion, */
+ ptr--; /* but an empty \Q\E sequence is OK. */
+ errorcode = ERR28;
+ goto FAILED;
+ }
+ if (!inverbname && after_manual_callout-- <= 0)
+ parsed_pattern = manage_callouts(thisptr, &previous_callout,
+ auto_callout, parsed_pattern, cb);
+ PARSED_LITERAL(c, parsed_pattern);
+ meta_quantifier = 0;
+ }
+ continue; /* Next character */
+ }
+
+ /* If we are processing the "name" part of a (*VERB:NAME) item, all
+ characters up to the closing parenthesis are literals except when
+ PCRE2_ALT_VERBNAMES is set. That causes backslash interpretation, but only \Q
+ and \E and escaped characters are allowed (no character types such as \d). If
+ PCRE2_EXTENDED is also set, we must ignore white space and # comments. Do
+ this by not entering the special (*VERB:NAME) processing - they are then
+ picked up below. Note that c is a character, not a code unit, so we must not
+ use MAX_255 to test its size because MAX_255 tests code units and is assumed
+ TRUE in 8-bit mode. */
+
+ if (inverbname &&
+ (
+ /* EITHER: not both options set */
+ ((options & (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) !=
+ (PCRE2_EXTENDED | PCRE2_ALT_VERBNAMES)) ||
+#ifdef SUPPORT_UNICODE
+ /* OR: character > 255 AND not Unicode Pattern White Space */
+ (c > 255 && (c|1) != 0x200f && (c|1) != 0x2029) ||
+#endif
+ /* OR: not a # comment or isspace() white space */
+ (c < 256 && c != CHAR_NUMBER_SIGN && (cb->ctypes[c] & ctype_space) == 0
+#ifdef SUPPORT_UNICODE
+ /* and not CHAR_NEL when Unicode is supported */
+ && c != CHAR_NEL
+#endif
+ )))
+ {
+ PCRE2_SIZE verbnamelength;
+
+ switch(c)
+ {
+ default:
+ PARSED_LITERAL(c, parsed_pattern);
+ break;
+
+ case CHAR_RIGHT_PARENTHESIS:
+ inverbname = FALSE;
+ okquantifier = FALSE; /* Was probably set by literals */
+ /* This is the length in characters */
+ verbnamelength = (PCRE2_SIZE)(parsed_pattern - verblengthptr - 1);
+ /* But the limit on the length is in code units */
+ if (ptr - verbnamestart - 1 > (int)MAX_MARK)
+ {
+ ptr--;
+ errorcode = ERR76;
+ goto FAILED;
+ }
+ *verblengthptr = (uint32_t)verbnamelength;
+
+ /* If this name was on a verb such as (*ACCEPT) which does not continue,
+ a (*MARK) was generated for the name. We now add the original verb as the
+ next item. */
+
+ if (add_after_mark != 0)
+ {
+ *parsed_pattern++ = add_after_mark;
+ add_after_mark = 0;
+ }
+ break;
+
+ case CHAR_BACKSLASH:
+ if ((options & PCRE2_ALT_VERBNAMES) != 0)
+ {
+ escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+ FALSE, cb);
+ if (errorcode != 0) goto FAILED;
+ }
+ else escape = 0; /* Treat all as literal */
+
+ switch(escape)
+ {
+ case 0:
+ PARSED_LITERAL(c, parsed_pattern);
+ break;
+
+ case ESC_Q:
+ inescq = TRUE;
+ break;
+
+ case ESC_E: /* Ignore */
+ break;
+
+ default:
+ errorcode = ERR40; /* Invalid in verb name */
+ goto FAILED;
+ }
+ }
+ continue; /* Next character in pattern */
+ }
+
+ /* Not a verb name character. At this point we must process everything that
+ must not change the quantification state. This is mainly comments, but we
+ handle \Q and \E here as well, so that an item such as A\Q\E+ is treated as
+ A+, as in Perl. An isolated \E is ignored. */
+
+ if (c == CHAR_BACKSLASH && ptr < ptrend)
+ {
+ if (*ptr == CHAR_Q || *ptr == CHAR_E)
+ {
+ inescq = *ptr == CHAR_Q;
+ ptr++;
+ continue;
+ }
+ }
+
+ /* Skip over whitespace and # comments in extended mode. Note that c is a
+ character, not a code unit, so we must not use MAX_255 to test its size
+ because MAX_255 tests code units and is assumed TRUE in 8-bit mode. The
+ whitespace characters are those designated as "Pattern White Space" by
+ Unicode, which are the isspace() characters plus CHAR_NEL (newline), which is
+ U+0085 in Unicode, plus U+200E, U+200F, U+2028, and U+2029. These are a
+ subset of space characters that match \h and \v. */
+
+ if ((options & PCRE2_EXTENDED) != 0)
+ {
+ if (c < 256 && (cb->ctypes[c] & ctype_space) != 0) continue;
+#ifdef SUPPORT_UNICODE
+ if (c == CHAR_NEL || (c|1) == 0x200f || (c|1) == 0x2029) continue;
+#endif
+ if (c == CHAR_NUMBER_SIGN)
+ {
+ while (ptr < ptrend)
+ {
+ if (IS_NEWLINE(ptr)) /* For non-fixed-length newline cases, */
+ { /* IS_NEWLINE sets cb->nllen. */
+ ptr += cb->nllen;
+ break;
+ }
+ ptr++;
+#ifdef SUPPORT_UNICODE
+ if (utf) FORWARDCHARTEST(ptr, ptrend);
+#endif
+ }
+ continue; /* Next character in pattern */
+ }
+ }
+
+ /* Skip over bracketed comments */
+
+ if (c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 2 &&
+ ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN)
+ {
+ while (++ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS);
+ if (ptr >= ptrend)
+ {
+ errorcode = ERR18; /* A special error for missing ) in a comment */
+ goto FAILED; /* to make it easier to debug. */
+ }
+ ptr++;
+ continue; /* Next character in pattern */
+ }
+
+ /* If the next item is not a quantifier, fill in length of any previous
+ callout and create an auto callout if required. */
+
+ if (c != CHAR_ASTERISK && c != CHAR_PLUS && c != CHAR_QUESTION_MARK &&
+ (c != CHAR_LEFT_CURLY_BRACKET ||
+ (tempptr = ptr,
+ !read_repeat_counts(&tempptr, ptrend, NULL, NULL, &errorcode))))
+ {
+ if (after_manual_callout-- <= 0)
+ parsed_pattern = manage_callouts(thisptr, &previous_callout, auto_callout,
+ parsed_pattern, cb);
+ }
+
+ /* If expect_cond_assert is 2, we have just passed (?( and are expecting an
+ assertion, possibly preceded by a callout. If the value is 1, we have just
+ had the callout and expect an assertion. There must be at least 3 more
+ characters in all cases. When expect_cond_assert is 2, we know that the
+ current character is an opening parenthesis, as otherwise we wouldn't be
+ here. However, when it is 1, we need to check, and it's easiest just to check
+ always. Note that expect_cond_assert may be negative, since all callouts just
+ decrement it. */
+
+ if (expect_cond_assert > 0)
+ {
+ BOOL ok = c == CHAR_LEFT_PARENTHESIS && ptrend - ptr >= 3 &&
+ ptr[0] == CHAR_QUESTION_MARK;
+ if (ok) switch(ptr[1])
+ {
+ case CHAR_C:
+ ok = expect_cond_assert == 2;
+ break;
+
+ case CHAR_EQUALS_SIGN:
+ case CHAR_EXCLAMATION_MARK:
+ break;
+
+ case CHAR_LESS_THAN_SIGN:
+ ok = ptr[2] == CHAR_EQUALS_SIGN || ptr[2] == CHAR_EXCLAMATION_MARK;
+ break;
+
+ default:
+ ok = FALSE;
+ }
+
+ if (!ok)
+ {
+ ptr--; /* Adjust error offset */
+ errorcode = ERR28;
+ goto FAILED;
+ }
+ }
+
+ /* Remember whether we are expecting a conditional assertion, and set the
+ default for this item. */
+
+ prev_expect_cond_assert = expect_cond_assert;
+ expect_cond_assert = 0;
+
+ /* Remember quantification status for the previous significant item, then set
+ default for this item. */
+
+ prev_okquantifier = okquantifier;
+ prev_meta_quantifier = meta_quantifier;
+ okquantifier = FALSE;
+ meta_quantifier = 0;
+
+ /* If the previous significant item was a quantifier, adjust the parsed code
+ if there is a following modifier. The base meta value is always followed by
+ the PLUS and QUERY values, in that order. We do this here rather than after
+ reading a quantifier so that intervening comments and /x whitespace can be
+ ignored without having to replicate code. */
+
+ if (prev_meta_quantifier != 0 && (c == CHAR_QUESTION_MARK || c == CHAR_PLUS))
+ {
+ parsed_pattern[(prev_meta_quantifier == META_MINMAX)? -3 : -1] =
+ prev_meta_quantifier + ((c == CHAR_QUESTION_MARK)?
+ 0x00020000u : 0x00010000u);
+ continue; /* Next character in pattern */
+ }
+
+
+ /* Process the next item in the main part of a pattern. */
+
+ switch(c)
+ {
+ default: /* Non-special character */
+ PARSED_LITERAL(c, parsed_pattern);
+ break;
+
+
+ /* ---- Escape sequence ---- */
+
+ case CHAR_BACKSLASH:
+ tempptr = ptr;
+ escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode, options,
+ FALSE, cb);
+ if (errorcode != 0)
+ {
+ ESCAPE_FAILED:
+ if ((cb->cx->extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
+ goto FAILED;
+ ptr = tempptr;
+ if (ptr >= ptrend) c = CHAR_BACKSLASH; else
+ {
+ GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */
+ }
+ escape = 0; /* Treat as literal character */
+ }
+
+ /* The escape was a data escape or literal character. */
+
+ if (escape == 0)
+ {
+ PARSED_LITERAL(c, parsed_pattern);
+ }
+
+ /* The escape was a back (or forward) reference. We keep the offset in
+ order to give a more useful diagnostic for a bad forward reference. For
+ references to groups numbered less than 10 we can't use more than two items
+ in parsed_pattern because they may be just two characters in the input (and
+ in a 64-bit world an offset may need two elements). So for them, the offset
+ of the first occurrent is held in a special vector. */
+
+ else if (escape < 0)
+ {
+ offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 1);
+ escape = -escape;
+ *parsed_pattern++ = META_BACKREF | (uint32_t)escape;
+ if (escape < 10)
+ {
+ if (cb->small_ref_offset[escape] == PCRE2_UNSET)
+ cb->small_ref_offset[escape] = offset;
+ }
+ else
+ {
+ PUTOFFSET(offset, parsed_pattern);
+ }
+ okquantifier = TRUE;
+ }
+
+ /* The escape was a character class such as \d etc. or other special
+ escape indicator such as \A or \X. Most of them generate just a single
+ parsed item, but \P and \p are followed by a 16-bit type and a 16-bit
+ value. They are supported only when Unicode is available. The type and
+ value are packed into a single 32-bit value so that the whole sequences
+ uses only two elements in the parsed_vector. This is because the same
+ coding is used if \d (for example) is turned into \p{Nd} when PCRE2_UCP is
+ set.
+
+ There are also some cases where the escape sequence is followed by a name:
+ \k{name}, \k<name>, and \k'name' are backreferences by name, and \g<name>
+ and \g'name' are subroutine calls by name; \g{name} is a synonym for
+ \k{name}. Note that \g<number> and \g'number' are handled by check_escape()
+ and returned as a negative value (handled above). A name is coded as an
+ offset into the pattern and a length. */
+
+ else switch (escape)
+ {
+ case ESC_C:
+#ifdef NEVER_BACKSLASH_C
+ errorcode = ERR85;
+ goto ESCAPE_FAILED;
+#else
+ if ((options & PCRE2_NEVER_BACKSLASH_C) != 0)
+ {
+ errorcode = ERR83;
+ goto ESCAPE_FAILED;
+ }
+#endif
+ okquantifier = TRUE;
+ *parsed_pattern++ = META_ESCAPE + escape;
+ break;
+
+ case ESC_X:
+#ifndef SUPPORT_UNICODE
+ errorcode = ERR45; /* Supported only with Unicode support */
+ goto ESCAPE_FAILED;
+#endif
+ case ESC_H:
+ case ESC_h:
+ case ESC_N:
+ case ESC_R:
+ case ESC_V:
+ case ESC_v:
+ okquantifier = TRUE;
+ *parsed_pattern++ = META_ESCAPE + escape;
+ break;
+
+ default: /* \A, \B, \b, \G, \K, \Z, \z cannot be quantified. */
+ *parsed_pattern++ = META_ESCAPE + escape;
+ break;
+
+ /* Escapes that change in UCP mode. Note that PCRE2_UCP will never be set
+ without Unicode support because it is checked when pcre2_compile() is
+ called. */
+
+ case ESC_d:
+ case ESC_D:
+ case ESC_s:
+ case ESC_S:
+ case ESC_w:
+ case ESC_W:
+ okquantifier = TRUE;
+ if ((options & PCRE2_UCP) == 0)
+ {
+ *parsed_pattern++ = META_ESCAPE + escape;
+ }
+ else
+ {
+ *parsed_pattern++ = META_ESCAPE +
+ ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
+ ESC_p : ESC_P);
+ switch(escape)
+ {
+ case ESC_d:
+ case ESC_D:
+ *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+ break;
+
+ case ESC_s:
+ case ESC_S:
+ *parsed_pattern++ = PT_SPACE << 16;
+ break;
+
+ case ESC_w:
+ case ESC_W:
+ *parsed_pattern++ = PT_WORD << 16;
+ break;
+ }
+ }
+ break;
+
+ /* Unicode property matching */
+
+ case ESC_P:
+ case ESC_p:
+#ifdef SUPPORT_UNICODE
+ {
+ BOOL negated;
+ uint16_t ptype = 0, pdata = 0;
+ if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb))
+ goto ESCAPE_FAILED;
+ if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P;
+ *parsed_pattern++ = META_ESCAPE + escape;
+ *parsed_pattern++ = (ptype << 16) | pdata;
+ okquantifier = TRUE;
+ }
+#else
+ errorcode = ERR45;
+ goto ESCAPE_FAILED;
+#endif
+ break; /* End \P and \p */
+
+ /* When \g is used with quotes or angle brackets as delimiters, it is a
+ numerical or named subroutine call, and control comes here. When used
+ with brace delimiters it is a numberical back reference and does not come
+ here because check_escape() returns it directly as a reference. \k is
+ always a named back reference. */
+
+ case ESC_g:
+ case ESC_k:
+ if (ptr >= ptrend || (*ptr != CHAR_LEFT_CURLY_BRACKET &&
+ *ptr != CHAR_LESS_THAN_SIGN && *ptr != CHAR_APOSTROPHE))
+ {
+ errorcode = (escape == ESC_g)? ERR57 : ERR69;
+ goto ESCAPE_FAILED;
+ }
+ terminator = (*ptr == CHAR_LESS_THAN_SIGN)?
+ CHAR_GREATER_THAN_SIGN : (*ptr == CHAR_APOSTROPHE)?
+ CHAR_APOSTROPHE : CHAR_RIGHT_CURLY_BRACKET;
+
+ /* For a non-braced \g, check for a numerical recursion. */
+
+ if (escape == ESC_g && terminator != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ PCRE2_SPTR p = ptr + 1;
+
+ if (read_number(&p, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i,
+ &errorcode))
+ {
+ if (p >= ptrend || *p != terminator)
+ {
+ errorcode = ERR57;
+ goto ESCAPE_FAILED;
+ }
+ ptr = p;
+ goto SET_RECURSION;
+ }
+ if (errorcode != 0) goto ESCAPE_FAILED;
+ }
+
+ /* Not a numerical recursion */
+
+ if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen,
+ &errorcode, cb)) goto ESCAPE_FAILED;
+
+ /* \k and \g when used with braces are back references, whereas \g used
+ with quotes or angle brackets is a recursion */
+
+ *parsed_pattern++ =
+ (escape == ESC_k || terminator == CHAR_RIGHT_CURLY_BRACKET)?
+ META_BACKREF_BYNAME : META_RECURSE_BYNAME;
+ *parsed_pattern++ = namelen;
+
+ PUTOFFSET(offset, parsed_pattern);
+ okquantifier = TRUE;
+ break; /* End special escape processing */
+ }
+ break; /* End escape sequence processing */
+
+
+ /* ---- Single-character special items ---- */
+
+ case CHAR_CIRCUMFLEX_ACCENT:
+ *parsed_pattern++ = META_CIRCUMFLEX;
+ break;
+
+ case CHAR_DOLLAR_SIGN:
+ *parsed_pattern++ = META_DOLLAR;
+ break;
+
+ case CHAR_DOT:
+ *parsed_pattern++ = META_DOT;
+ okquantifier = TRUE;
+ break;
+
+
+ /* ---- Single-character quantifiers ---- */
+
+ case CHAR_ASTERISK:
+ meta_quantifier = META_ASTERISK;
+ goto CHECK_QUANTIFIER;
+
+ case CHAR_PLUS:
+ meta_quantifier = META_PLUS;
+ goto CHECK_QUANTIFIER;
+
+ case CHAR_QUESTION_MARK:
+ meta_quantifier = META_QUERY;
+ goto CHECK_QUANTIFIER;
+
+
+ /* ---- Potential {n,m} quantifier ---- */
+
+ case CHAR_LEFT_CURLY_BRACKET:
+ if (!read_repeat_counts(&ptr, ptrend, &min_repeat, &max_repeat,
+ &errorcode))
+ {
+ if (errorcode != 0) goto FAILED; /* Error in quantifier. */
+ PARSED_LITERAL(c, parsed_pattern); /* Not a quantifier */
+ break; /* No more quantifier processing */
+ }
+ meta_quantifier = META_MINMAX;
+ /* Fall through */
+
+
+ /* ---- Quantifier post-processing ---- */
+
+ /* Check that a quantifier is allowed after the previous item. */
+
+ CHECK_QUANTIFIER:
+ if (!prev_okquantifier)
+ {
+ errorcode = ERR9;
+ goto FAILED_BACK;
+ }
+
+ /* Now we can put the quantifier into the parsed pattern vector. At this
+ stage, we have only the basic quantifier. The check for a following + or ?
+ modifier happens at the top of the loop, after any intervening comments
+ have been removed. */
+
+ *parsed_pattern++ = meta_quantifier;
+ if (c == CHAR_LEFT_CURLY_BRACKET)
+ {
+ *parsed_pattern++ = min_repeat;
+ *parsed_pattern++ = max_repeat;
+ }
+ break;
+
+
+ /* ---- Character class ---- */
+
+ case CHAR_LEFT_SQUARE_BRACKET:
+ okquantifier = TRUE;
+
+ /* In another (POSIX) regex library, the ugly syntax [[:<:]] and [[:>:]] is
+ used for "start of word" and "end of word". As these are otherwise illegal
+ sequences, we don't break anything by recognizing them. They are replaced
+ by \b(?=\w) and \b(?<=\w) respectively. Sequences like [a[:<:]] are
+ erroneous and are handled by the normal code below. */
+
+ if (ptrend - ptr >= 6 &&
+ (PRIV(strncmp_c8)(ptr, STRING_WEIRD_STARTWORD, 6) == 0 ||
+ PRIV(strncmp_c8)(ptr, STRING_WEIRD_ENDWORD, 6) == 0))
+ {
+ *parsed_pattern++ = META_ESCAPE + ESC_b;
+
+ if (ptr[2] == CHAR_LESS_THAN_SIGN)
+ {
+ *parsed_pattern++ = META_LOOKAHEAD;
+ }
+ else
+ {
+ *parsed_pattern++ = META_LOOKBEHIND;
+ *has_lookbehind = TRUE;
+
+ /* The offset is used only for the "non-fixed length" error; this won't
+ occur here, so just store zero. */
+
+ PUTOFFSET((PCRE2_SIZE)0, parsed_pattern);
+ }
+
+ if ((options & PCRE2_UCP) == 0)
+ *parsed_pattern++ = META_ESCAPE + ESC_w;
+ else
+ {
+ *parsed_pattern++ = META_ESCAPE + ESC_p;
+ *parsed_pattern++ = PT_WORD << 16;
+ }
+ *parsed_pattern++ = META_KET;
+ ptr += 6;
+ break;
+ }
+
+ /* PCRE supports POSIX class stuff inside a class. Perl gives an error if
+ they are encountered at the top level, so we'll do that too. */
+
+ if (ptr < ptrend && (*ptr == CHAR_COLON || *ptr == CHAR_DOT ||
+ *ptr == CHAR_EQUALS_SIGN) &&
+ check_posix_syntax(ptr, ptrend, &tempptr))
+ {
+ errorcode = (*ptr-- == CHAR_COLON)? ERR12 : ERR13;
+ goto FAILED;
+ }
+
+ /* Process a regular character class. If the first character is '^', set
+ the negation flag. If the first few characters (either before or after ^)
+ are \Q\E or \E or space or tab in extended-more mode, we skip them too.
+ This makes for compatibility with Perl. */
+
+ negate_class = FALSE;
+ while (ptr < ptrend)
+ {
+ GETCHARINCTEST(c, ptr);
+ if (c == CHAR_BACKSLASH)
+ {
+ if (ptr < ptrend && *ptr == CHAR_E) ptr++;
+ else if (ptrend - ptr >= 3 &&
+ PRIV(strncmp_c8)(ptr, STR_Q STR_BACKSLASH STR_E, 3) == 0)
+ ptr += 3;
+ else
+ break;
+ }
+ else if ((options & PCRE2_EXTENDED_MORE) != 0 &&
+ (c == CHAR_SPACE || c == CHAR_HT)) /* Note: just these two */
+ continue;
+ else if (!negate_class && c == CHAR_CIRCUMFLEX_ACCENT)
+ negate_class = TRUE;
+ else break;
+ }
+
+ /* Now the real contents of the class; c has the first "real" character.
+ Empty classes are permitted only if the option is set. */
+
+ if (c == CHAR_RIGHT_SQUARE_BRACKET &&
+ (cb->external_options & PCRE2_ALLOW_EMPTY_CLASS) != 0)
+ {
+ *parsed_pattern++ = negate_class? META_CLASS_EMPTY_NOT : META_CLASS_EMPTY;
+ break; /* End of class processing */
+ }
+
+ /* Process a non-empty class. */
+
+ *parsed_pattern++ = negate_class? META_CLASS_NOT : META_CLASS;
+ class_range_state = RANGE_NO;
+
+ /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+ because there are holes in the encoding, and simply using the range A-Z
+ (for example) would include the characters in the holes. This applies only
+ to ranges where both values are literal; [\xC1-\xE9] is different to [A-Z]
+ in this respect. In order to accommodate this, we keep track of whether
+ character values are literal or not, and a state variable for handling
+ ranges. */
+
+ /* Loop for the contents of the class */
+
+ for (;;)
+ {
+ BOOL char_is_literal = TRUE;
+
+ /* Inside \Q...\E everything is literal except \E */
+
+ if (inescq)
+ {
+ if (c == CHAR_BACKSLASH && ptr < ptrend && *ptr == CHAR_E)
+ {
+ inescq = FALSE; /* Reset literal state */
+ ptr++; /* Skip the 'E' */
+ goto CLASS_CONTINUE;
+ }
+ goto CLASS_LITERAL;
+ }
+
+ /* Skip over space and tab (only) in extended-more mode. */
+
+ if ((options & PCRE2_EXTENDED_MORE) != 0 &&
+ (c == CHAR_SPACE || c == CHAR_HT))
+ goto CLASS_CONTINUE;
+
+ /* Handle POSIX class names. Perl allows a negation extension of the
+ form [:^name:]. A square bracket that doesn't match the syntax is
+ treated as a literal. We also recognize the POSIX constructions
+ [.ch.] and [=ch=] ("collating elements") and fault them, as Perl
+ 5.6 and 5.8 do. */
+
+ if (c == CHAR_LEFT_SQUARE_BRACKET &&
+ ptrend - ptr >= 3 &&
+ (*ptr == CHAR_COLON || *ptr == CHAR_DOT ||
+ *ptr == CHAR_EQUALS_SIGN) &&
+ check_posix_syntax(ptr, ptrend, &tempptr))
+ {
+ BOOL posix_negate = FALSE;
+ int posix_class;
+
+ /* Perl treats a hyphen before a POSIX class as a literal, not the
+ start of a range. However, it gives a warning in its warning mode. PCRE
+ does not have a warning mode, so we give an error, because this is
+ likely an error on the user's part. */
+
+ if (class_range_state == RANGE_STARTED)
+ {
+ errorcode = ERR50;
+ goto FAILED;
+ }
+
+ if (*ptr != CHAR_COLON)
+ {
+ errorcode = ERR13;
+ goto FAILED_BACK;
+ }
+
+ if (*(++ptr) == CHAR_CIRCUMFLEX_ACCENT)
+ {
+ posix_negate = TRUE;
+ ptr++;
+ }
+
+ posix_class = check_posix_name(ptr, (int)(tempptr - ptr));
+ if (posix_class < 0)
+ {
+ errorcode = ERR30;
+ goto FAILED;
+ }
+ ptr = tempptr + 2;
+
+ /* Perl treats a hyphen after a POSIX class as a literal, not the
+ start of a range. However, it gives a warning in its warning mode
+ unless the hyphen is the last character in the class. PCRE does not
+ have a warning mode, so we give an error, because this is likely an
+ error on the user's part. */
+
+ if (ptr < ptrend - 1 && *ptr == CHAR_MINUS &&
+ ptr[1] != CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ errorcode = ERR50;
+ goto FAILED;
+ }
+
+ /* Set "a hyphen is not the start of a range" for the -] case, and also
+ in case the POSIX class is followed by \E or \Q\E (possibly repeated -
+ fuzzers do that kind of thing) and *then* a hyphen. This causes that
+ hyphen to be treated as a literal. I don't think it's worth setting up
+ special apparatus to do otherwise. */
+
+ class_range_state = RANGE_NO;
+
+ /* When PCRE2_UCP is set, some of the POSIX classes are converted to
+ use Unicode properties \p or \P or, in one case, \h or \H. The
+ substitutes table has two values per class, containing the type and
+ value of a \p or \P item. The special cases are specified with a
+ negative type: a non-zero value causes \h or \H to be used, and a zero
+ value falls through to behave like a non-UCP POSIX class. */
+
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UCP) != 0)
+ {
+ int ptype = posix_substitutes[2*posix_class];
+ int pvalue = posix_substitutes[2*posix_class + 1];
+ if (ptype >= 0)
+ {
+ *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_P : ESC_p);
+ *parsed_pattern++ = (ptype << 16) | pvalue;
+ goto CLASS_CONTINUE;
+ }
+
+ if (pvalue != 0)
+ {
+ *parsed_pattern++ = META_ESCAPE + (posix_negate? ESC_H : ESC_h);
+ goto CLASS_CONTINUE;
+ }
+
+ /* Fall through */
+ }
+#endif /* SUPPORT_UNICODE */
+
+ /* Non-UCP POSIX class */
+
+ *parsed_pattern++ = posix_negate? META_POSIX_NEG : META_POSIX;
+ *parsed_pattern++ = posix_class;
+ }
+
+ /* Handle potential start of range */
+
+ else if (c == CHAR_MINUS && class_range_state >= RANGE_OK_ESCAPED)
+ {
+ *parsed_pattern++ = (class_range_state == RANGE_OK_LITERAL)?
+ META_RANGE_LITERAL : META_RANGE_ESCAPED;
+ class_range_state = RANGE_STARTED;
+ }
+
+ /* Handle a literal character */
+
+ else if (c != CHAR_BACKSLASH)
+ {
+ CLASS_LITERAL:
+ if (class_range_state == RANGE_STARTED)
+ {
+ if (c == parsed_pattern[-2]) /* Optimize one-char range */
+ parsed_pattern--;
+ else if (parsed_pattern[-2] > c) /* Check range is in order */
+ {
+ errorcode = ERR8;
+ goto FAILED_BACK;
+ }
+ else
+ {
+ if (!char_is_literal && parsed_pattern[-1] == META_RANGE_LITERAL)
+ parsed_pattern[-1] = META_RANGE_ESCAPED;
+ PARSED_LITERAL(c, parsed_pattern);
+ }
+ class_range_state = RANGE_NO;
+ }
+ else /* Potential start of range */
+ {
+ class_range_state = char_is_literal?
+ RANGE_OK_LITERAL : RANGE_OK_ESCAPED;
+ PARSED_LITERAL(c, parsed_pattern);
+ }
+ }
+
+ /* Handle escapes in a class */
+
+ else
+ {
+ tempptr = ptr;
+ escape = PRIV(check_escape)(&ptr, ptrend, &c, &errorcode,
+ options, TRUE, cb);
+ if (errorcode != 0)
+ {
+ CLASS_ESCAPE_FAILED:
+ if ((cb->cx->extra_options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) == 0)
+ goto FAILED;
+ ptr = tempptr;
+ if (ptr >= ptrend) c = CHAR_BACKSLASH; else
+ {
+ GETCHARINCTEST(c, ptr); /* Get character value, increment pointer */
+ }
+ escape = 0; /* Treat as literal character */
+ }
+
+ if (escape == 0) /* Escaped character code point is in c */
+ {
+ char_is_literal = FALSE;
+ goto CLASS_LITERAL;
+ }
+
+ /* These three escapes do not alter the class range state. */
+
+ if (escape == ESC_b)
+ {
+ c = CHAR_BS; /* \b is backspace in a class */
+ char_is_literal = FALSE;
+ goto CLASS_LITERAL;
+ }
+
+ else if (escape == ESC_Q)
+ {
+ inescq = TRUE; /* Enter literal mode */
+ goto CLASS_CONTINUE;
+ }
+
+ else if (escape == ESC_E) /* Ignore orphan \E */
+ goto CLASS_CONTINUE;
+
+ /* The second part of a range can be a single-character escape
+ sequence (detected above), but not any of the other escapes. Perl
+ treats a hyphen as a literal in such circumstances. However, in Perl's
+ warning mode, a warning is given, so PCRE now faults it, as it is
+ almost certainly a mistake on the user's part. */
+
+ if (class_range_state == RANGE_STARTED)
+ {
+ errorcode = ERR50;
+ goto CLASS_ESCAPE_FAILED;
+ }
+
+ /* Of the remaining escapes, only those that define characters are
+ allowed in a class. None may start a range. */
+
+ class_range_state = RANGE_NO;
+ switch(escape)
+ {
+ case ESC_N:
+ errorcode = ERR71; /* Not supported in a class */
+ goto CLASS_ESCAPE_FAILED;
+
+ case ESC_H:
+ case ESC_h:
+ case ESC_V:
+ case ESC_v:
+ *parsed_pattern++ = META_ESCAPE + escape;
+ break;
+
+ /* These escapes are converted to Unicode property tests when
+ PCRE2_UCP is set. */
+
+ case ESC_d:
+ case ESC_D:
+ case ESC_s:
+ case ESC_S:
+ case ESC_w:
+ case ESC_W:
+ if ((options & PCRE2_UCP) == 0)
+ {
+ *parsed_pattern++ = META_ESCAPE + escape;
+ }
+ else
+ {
+ *parsed_pattern++ = META_ESCAPE +
+ ((escape == ESC_d || escape == ESC_s || escape == ESC_w)?
+ ESC_p : ESC_P);
+ switch(escape)
+ {
+ case ESC_d:
+ case ESC_D:
+ *parsed_pattern++ = (PT_PC << 16) | ucp_Nd;
+ break;
+
+ case ESC_s:
+ case ESC_S:
+ *parsed_pattern++ = PT_SPACE << 16;
+ break;
+
+ case ESC_w:
+ case ESC_W:
+ *parsed_pattern++ = PT_WORD << 16;
+ break;
+ }
+ }
+ break;
+
+ /* Explicit Unicode property matching */
+
+ case ESC_P:
+ case ESC_p:
+#ifdef SUPPORT_UNICODE
+ {
+ BOOL negated;
+ uint16_t ptype = 0, pdata = 0;
+ if (!get_ucp(&ptr, &negated, &ptype, &pdata, &errorcode, cb))
+ goto FAILED;
+ if (negated) escape = (escape == ESC_P)? ESC_p : ESC_P;
+ *parsed_pattern++ = META_ESCAPE + escape;
+ *parsed_pattern++ = (ptype << 16) | pdata;
+ }
+#else
+ errorcode = ERR45;
+ goto CLASS_ESCAPE_FAILED;
+#endif
+ break; /* End \P and \p */
+
+ default: /* All others are not allowed in a class */
+ errorcode = ERR7;
+ ptr--;
+ goto CLASS_ESCAPE_FAILED;
+ }
+
+ /* Perl gives a warning unless a following hyphen is the last character
+ in the class. PCRE throws an error. */
+
+ if (ptr < ptrend - 1 && *ptr == CHAR_MINUS &&
+ ptr[1] != CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ errorcode = ERR50;
+ goto FAILED;
+ }
+ }
+
+ /* Proceed to next thing in the class. */
+
+ CLASS_CONTINUE:
+ if (ptr >= ptrend)
+ {
+ errorcode = ERR6; /* Missing terminating ']' */
+ goto FAILED;
+ }
+ GETCHARINCTEST(c, ptr);
+ if (c == CHAR_RIGHT_SQUARE_BRACKET && !inescq) break;
+ } /* End of class-processing loop */
+
+ if (class_range_state == RANGE_STARTED)
+ {
+ parsed_pattern[-1] = CHAR_MINUS;
+ class_range_state = RANGE_NO;
+ }
+
+ *parsed_pattern++ = META_CLASS_END;
+ break; /* End of character class */
+
+
+ /* ---- Opening parenthesis ---- */
+
+ case CHAR_LEFT_PARENTHESIS:
+ if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+ /* If ( is not followed by ? it is either a capture or a special verb. */
+
+ if (*ptr != CHAR_QUESTION_MARK)
+ {
+ const char *vn;
+
+ /* Handle capturing brackets (or non-capturing if auto-capture is turned
+ off). */
+
+ if (*ptr != CHAR_ASTERISK)
+ {
+ nest_depth++;
+ if ((options & PCRE2_NO_AUTO_CAPTURE) == 0)
+ {
+ cb->bracount++;
+ *parsed_pattern++ = META_CAPTURE | cb->bracount;
+ }
+ else *parsed_pattern++ = META_NOCAPTURE;
+ }
+
+
+ /* ---- Handle (*VERB) and (*VERB:NAME) ---- */
+
+ /* Do nothing for (*) so it gives a "bad quantifier" error rather than
+ "(*MARK) must have an argument". */
+
+ else if (ptrend - ptr > 1 && ptr[1] != CHAR_RIGHT_PARENTHESIS)
+ {
+ vn = verbnames;
+ if (!read_name(&ptr, ptrend, 0, &offset, &name, &namelen, &errorcode,
+ cb)) goto FAILED;
+ if (ptr >= ptrend || (*ptr != CHAR_COLON &&
+ *ptr != CHAR_RIGHT_PARENTHESIS))
+ {
+ errorcode = ERR60; /* Malformed */
+ goto FAILED;
+ }
+
+ /* Scan the table of verb names */
+
+ for (i = 0; i < verbcount; i++)
+ {
+ if (namelen == verbs[i].len &&
+ PRIV(strncmp_c8)(name, vn, namelen) == 0)
+ break;
+ vn += verbs[i].len + 1;
+ }
+
+ if (i >= verbcount)
+ {
+ errorcode = ERR60; /* Verb not recognized */
+ goto FAILED;
+ }
+
+ /* An empty argument is treated as no argument. */
+
+ if (*ptr == CHAR_COLON && ptr + 1 < ptrend &&
+ ptr[1] == CHAR_RIGHT_PARENTHESIS)
+ ptr++; /* Advance to the closing parens */
+
+ /* Check for mandatory non-empty argument; this is (*MARK) */
+
+ if (verbs[i].has_arg > 0 && *ptr != CHAR_COLON)
+ {
+ errorcode = ERR66;
+ goto FAILED;
+ }
+
+ /* It appears that Perl allows any characters whatsoever, other than a
+ closing parenthesis, to appear in arguments ("names"), so we no longer
+ insist on letters, digits, and underscores. Perl does not, however, do
+ any interpretation within arguments, and has no means of including a
+ closing parenthesis. PCRE supports escape processing but only when it
+ is requested by an option. We set inverbname TRUE here, and let the
+ main loop take care of this so that escape and \x processing is done by
+ the main code above. */
+
+ if (*ptr++ == CHAR_COLON) /* Skip past : or ) */
+ {
+ /* Some optional arguments can be treated as a preceding (*MARK) */
+
+ if (verbs[i].has_arg < 0)
+ {
+ add_after_mark = verbs[i].meta;
+ *parsed_pattern++ = META_MARK;
+ }
+
+ /* The remaining verbs with arguments (except *MARK) need a different
+ opcode. */
+
+ else
+ {
+ *parsed_pattern++ = verbs[i].meta +
+ ((verbs[i].meta != META_MARK)? 0x00010000u:0);
+ }
+
+ /* Set up for reading the name in the main loop. */
+
+ verblengthptr = parsed_pattern++;
+ verbnamestart = ptr;
+ inverbname = TRUE;
+ }
+ else /* No verb "name" argument */
+ {
+ *parsed_pattern++ = verbs[i].meta;
+ }
+ } /* End of (*VERB) handling */
+ break; /* Done with this parenthesis */
+ } /* End of groups that don't start with (? */
+
+
+ /* ---- Items starting (? ---- */
+
+ /* The type of item is determined by what follows (?. Handle (?| and option
+ changes under "default" because both need a new block on the nest stack.
+ Comments starting with (?# are handled above. Note that there is some
+ ambiguity about the sequence (?- because if a digit follows it's a relative
+ recursion or subroutine call whereas otherwise it's an option unsetting. */
+
+ if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+ switch(*ptr)
+ {
+ default:
+ if (*ptr == CHAR_MINUS && ptrend - ptr > 1 && IS_DIGIT(ptr[1]))
+ goto RECURSION_BYNUMBER; /* The + case is handled by CHAR_PLUS */
+
+ /* We now have either (?| or a (possibly empty) option setting,
+ optionally followed by a non-capturing group. */
+
+ nest_depth++;
+ if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+ else if (++top_nest >= end_nests)
+ {
+ errorcode = ERR84;
+ goto FAILED;
+ }
+ top_nest->nest_depth = nest_depth;
+ top_nest->flags = 0;
+ top_nest->options = options & PARSE_TRACKED_OPTIONS;
+
+ /* Start of non-capturing group that resets the capture count for each
+ branch. */
+
+ if (*ptr == CHAR_VERTICAL_LINE)
+ {
+ top_nest->reset_group = (uint16_t)cb->bracount;
+ top_nest->max_group = (uint16_t)cb->bracount;
+ top_nest->flags |= NSF_RESET;
+ cb->external_flags |= PCRE2_DUPCAPUSED;
+ *parsed_pattern++ = META_NOCAPTURE;
+ ptr++;
+ }
+
+ /* Scan for options imnsxJU to be set or unset. */
+
+ else
+ {
+ BOOL hyphenok = TRUE;
+ uint32_t oldoptions = options;
+
+ top_nest->reset_group = 0;
+ top_nest->max_group = 0;
+ set = unset = 0;
+ optset = &set;
+
+ /* ^ at the start unsets imnsx and disables the subsequent use of - */
+
+ if (ptr < ptrend && *ptr == CHAR_CIRCUMFLEX_ACCENT)
+ {
+ options &= ~(PCRE2_CASELESS|PCRE2_MULTILINE|PCRE2_NO_AUTO_CAPTURE|
+ PCRE2_DOTALL|PCRE2_EXTENDED|PCRE2_EXTENDED_MORE);
+ hyphenok = FALSE;
+ ptr++;
+ }
+
+ while (ptr < ptrend && *ptr != CHAR_RIGHT_PARENTHESIS &&
+ *ptr != CHAR_COLON)
+ {
+ switch (*ptr++)
+ {
+ case CHAR_MINUS:
+ if (!hyphenok)
+ {
+ errorcode = ERR94;
+ ptr--; /* Correct the offset */
+ goto FAILED;
+ }
+ optset = &unset;
+ hyphenok = FALSE;
+ break;
+
+ case CHAR_J: /* Record that it changed in the external options */
+ *optset |= PCRE2_DUPNAMES;
+ cb->external_flags |= PCRE2_JCHANGED;
+ break;
+
+ case CHAR_i: *optset |= PCRE2_CASELESS; break;
+ case CHAR_m: *optset |= PCRE2_MULTILINE; break;
+ case CHAR_n: *optset |= PCRE2_NO_AUTO_CAPTURE; break;
+ case CHAR_s: *optset |= PCRE2_DOTALL; break;
+ case CHAR_U: *optset |= PCRE2_UNGREEDY; break;
+
+ /* If x appears twice it sets the extended extended option. */
+
+ case CHAR_x:
+ *optset |= PCRE2_EXTENDED;
+ if (ptr < ptrend && *ptr == CHAR_x)
+ {
+ *optset |= PCRE2_EXTENDED_MORE;
+ ptr++;
+ }
+ break;
+
+ default:
+ errorcode = ERR11;
+ ptr--; /* Correct the offset */
+ goto FAILED;
+ }
+ }
+
+ /* If we are setting extended without extended-more, ensure that any
+ existing extended-more gets unset. Also, unsetting extended must also
+ unset extended-more. */
+
+ if ((set & (PCRE2_EXTENDED|PCRE2_EXTENDED_MORE)) == PCRE2_EXTENDED ||
+ (unset & PCRE2_EXTENDED) != 0)
+ unset |= PCRE2_EXTENDED_MORE;
+
+ options = (options | set) & (~unset);
+
+ /* If the options ended with ')' this is not the start of a nested
+ group with option changes, so the options change at this level.
+ In this case, if the previous level set up a nest block, discard the
+ one we have just created. Otherwise adjust it for the previous level.
+ If the options ended with ':' we are starting a non-capturing group,
+ possibly with an options setting. */
+
+ if (ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+ if (*ptr++ == CHAR_RIGHT_PARENTHESIS)
+ {
+ nest_depth--; /* This is not a nested group after all. */
+ if (top_nest > (nest_save *)(cb->start_workspace) &&
+ (top_nest-1)->nest_depth == nest_depth) top_nest--;
+ else top_nest->nest_depth = nest_depth;
+ }
+ else *parsed_pattern++ = META_NOCAPTURE;
+
+ /* If nothing changed, no need to record. */
+
+ if (options != oldoptions)
+ {
+ *parsed_pattern++ = META_OPTIONS;
+ *parsed_pattern++ = options;
+ }
+ } /* End options processing */
+ break; /* End default case after (? */
+
+
+ /* ---- Python syntax support ---- */
+
+ case CHAR_P:
+ if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+ /* (?P<name> is the same as (?<name>, which defines a named group. */
+
+ if (*ptr == CHAR_LESS_THAN_SIGN)
+ {
+ terminator = CHAR_GREATER_THAN_SIGN;
+ goto DEFINE_NAME;
+ }
+
+ /* (?P>name) is the same as (?&name), which is a recursion or subroutine
+ call. */
+
+ if (*ptr == CHAR_GREATER_THAN_SIGN) goto RECURSE_BY_NAME;
+
+ /* (?P=name) is the same as \k<name>, a back reference by name. Anything
+ else after (?P is an error. */
+
+ if (*ptr != CHAR_EQUALS_SIGN)
+ {
+ errorcode = ERR41;
+ goto FAILED;
+ }
+ if (!read_name(&ptr, ptrend, CHAR_RIGHT_PARENTHESIS, &offset, &name,
+ &namelen, &errorcode, cb)) goto FAILED;
+ *parsed_pattern++ = META_BACKREF_BYNAME;
+ *parsed_pattern++ = namelen;
+ PUTOFFSET(offset, parsed_pattern);
+ okquantifier = TRUE;
+ break; /* End of (?P processing */
+
+
+ /* ---- Recursion/subroutine calls by number ---- */
+
+ case CHAR_R:
+ i = 0; /* (?R) == (?R0) */
+ ptr++;
+ if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+ {
+ errorcode = ERR58;
+ goto FAILED;
+ }
+ goto SET_RECURSION;
+
+ /* An item starting (?- followed by a digit comes here via the "default"
+ case because (?- followed by a non-digit is an options setting. */
+
+ case CHAR_PLUS:
+ if (ptrend - ptr < 2 || !IS_DIGIT(ptr[1]))
+ {
+ errorcode = ERR29; /* Missing number */
+ goto FAILED;
+ }
+ /* Fall through */
+
+ case CHAR_0: case CHAR_1: case CHAR_2: case CHAR_3: case CHAR_4:
+ case CHAR_5: case CHAR_6: case CHAR_7: case CHAR_8: case CHAR_9:
+ RECURSION_BYNUMBER:
+ if (!read_number(&ptr, ptrend,
+ (IS_DIGIT(*ptr))? -1:(int)(cb->bracount), /* + and - are relative */
+ MAX_GROUP_NUMBER, ERR61,
+ &i, &errorcode)) goto FAILED;
+ if (i < 0) /* NB (?0) is permitted */
+ {
+ errorcode = ERR15; /* Unknown group */
+ goto FAILED_BACK;
+ }
+ if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+ goto UNCLOSED_PARENTHESIS;
+
+ SET_RECURSION:
+ *parsed_pattern++ = META_RECURSE | (uint32_t)i;
+ offset = (PCRE2_SIZE)(ptr - cb->start_pattern);
+ ptr++;
+ PUTOFFSET(offset, parsed_pattern);
+ okquantifier = TRUE;
+ break; /* End of recursive call by number handling */
+
+
+ /* ---- Recursion/subroutine calls by name ---- */
+
+ case CHAR_AMPERSAND:
+ RECURSE_BY_NAME:
+ if (!read_name(&ptr, ptrend, CHAR_RIGHT_PARENTHESIS, &offset, &name,
+ &namelen, &errorcode, cb)) goto FAILED;
+ *parsed_pattern++ = META_RECURSE_BYNAME;
+ *parsed_pattern++ = namelen;
+ PUTOFFSET(offset, parsed_pattern);
+ okquantifier = TRUE;
+ break;
+
+ /* ---- Callout with numerical or string argument ---- */
+
+ case CHAR_C:
+ if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+
+ /* If the previous item was a condition starting (?(? an assertion,
+ optionally preceded by a callout, is expected. This is checked later on,
+ during actual compilation. However we need to identify this kind of
+ assertion in this pass because it must not be qualified. The value of
+ expect_cond_assert is set to 2 after (?(? is processed. We decrement it
+ for a callout - still leaving a positive value that identifies the
+ assertion. Multiple callouts or any other items will make it zero or
+ less, which doesn't matter because they will cause an error later. */
+
+ expect_cond_assert = prev_expect_cond_assert - 1;
+
+ /* If previous_callout is not NULL, it means this follows a previous
+ callout. If it was a manual callout, do nothing; this means its "length
+ of next pattern item" field will remain zero. If it was an automatic
+ callout, abolish it. */
+
+ if (previous_callout != NULL && (options & PCRE2_AUTO_CALLOUT) != 0 &&
+ previous_callout == parsed_pattern - 4 &&
+ parsed_pattern[-1] == 255)
+ parsed_pattern = previous_callout;
+
+ /* Save for updating next pattern item length, and skip one item before
+ completing. */
+
+ previous_callout = parsed_pattern;
+ after_manual_callout = 1;
+
+ /* Handle a string argument; specific delimiter is required. */
+
+ if (*ptr != CHAR_RIGHT_PARENTHESIS && !IS_DIGIT(*ptr))
+ {
+ PCRE2_SIZE calloutlength;
+ PCRE2_SPTR startptr = ptr;
+
+ delimiter = 0;
+ for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+ {
+ if (*ptr == PRIV(callout_start_delims)[i])
+ {
+ delimiter = PRIV(callout_end_delims)[i];
+ break;
+ }
+ }
+ if (delimiter == 0)
+ {
+ errorcode = ERR82;
+ goto FAILED;
+ }
+
+ *parsed_pattern = META_CALLOUT_STRING;
+ parsed_pattern += 3; /* Skip pattern info */
+
+ for (;;)
+ {
+ if (++ptr >= ptrend)
+ {
+ errorcode = ERR81;
+ ptr = startptr; /* To give a more useful message */
+ goto FAILED;
+ }
+ if (*ptr == delimiter && (++ptr >= ptrend || *ptr != delimiter))
+ break;
+ }
+
+ calloutlength = (PCRE2_SIZE)(ptr - startptr);
+ if (calloutlength > UINT32_MAX)
+ {
+ errorcode = ERR72;
+ goto FAILED;
+ }
+ *parsed_pattern++ = (uint32_t)calloutlength;
+ offset = (PCRE2_SIZE)(startptr - cb->start_pattern);
+ PUTOFFSET(offset, parsed_pattern);
+ }
+
+ /* Handle a callout with an optional numerical argument, which must be
+ less than or equal to 255. A missing argument gives 0. */
+
+ else
+ {
+ int n = 0;
+ *parsed_pattern = META_CALLOUT_NUMBER; /* Numerical callout */
+ parsed_pattern += 3; /* Skip pattern info */
+ while (ptr < ptrend && IS_DIGIT(*ptr))
+ {
+ n = n * 10 + *ptr++ - CHAR_0;
+ if (n > 255)
+ {
+ errorcode = ERR38;
+ goto FAILED;
+ }
+ }
+ *parsed_pattern++ = n;
+ }
+
+ /* Both formats must have a closing parenthesis */
+
+ if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+ {
+ errorcode = ERR39;
+ goto FAILED;
+ }
+ ptr++;
+
+ /* Remember the offset to the next item in the pattern, and set a default
+ length. This should get updated after the next item is read. */
+
+ previous_callout[1] = (uint32_t)(ptr - cb->start_pattern);
+ previous_callout[2] = 0;
+ break; /* End callout */
+
+
+ /* ---- Conditional group ---- */
+
+ /* A condition can be an assertion, a number (referring to a numbered
+ group's having been set), a name (referring to a named group), or 'R',
+ referring to overall recursion. R<digits> and R&name are also permitted
+ for recursion state tests. Numbers may be preceded by + or - to specify a
+ relative group number.
+
+ There are several syntaxes for testing a named group: (?(name)) is used
+ by Python; Perl 5.10 onwards uses (?(<name>) or (?('name')).
+
+ There are two unfortunate ambiguities. 'R' can be the recursive thing or
+ the name 'R' (and similarly for 'R' followed by digits). 'DEFINE' can be
+ the Perl DEFINE feature or the Python named test. We look for a name
+ first; if not found, we try the other case.
+
+ For compatibility with auto-callouts, we allow a callout to be specified
+ before a condition that is an assertion. */
+
+ case CHAR_LEFT_PARENTHESIS:
+ if (++ptr >= ptrend) goto UNCLOSED_PARENTHESIS;
+ nest_depth++;
+
+ /* If the next character is ? there must be an assertion next (optionally
+ preceded by a callout). We do not check this here, but instead we set
+ expect_cond_assert to 2. If this is still greater than zero (callouts
+ decrement it) when the next assertion is read, it will be marked as a
+ condition that must not be repeated. A value greater than zero also
+ causes checking that an assertion (possibly with callout) follows. */
+
+ if (*ptr == CHAR_QUESTION_MARK)
+ {
+ *parsed_pattern++ = META_COND_ASSERT;
+ ptr--; /* Pull pointer back to the opening parenthesis. */
+ expect_cond_assert = 2;
+ break; /* End of conditional */
+ }
+
+ /* Handle (?([+-]number)... */
+
+ if (read_number(&ptr, ptrend, cb->bracount, MAX_GROUP_NUMBER, ERR61, &i,
+ &errorcode))
+ {
+ if (i <= 0)
+ {
+ errorcode = ERR15;
+ goto FAILED;
+ }
+ *parsed_pattern++ = META_COND_NUMBER;
+ offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2);
+ PUTOFFSET(offset, parsed_pattern);
+ *parsed_pattern++ = i;
+ }
+ else if (errorcode != 0) goto FAILED; /* Number too big */
+
+ /* No number found. Handle the special case (?(VERSION[>]=n.m)... */
+
+ else if (ptrend - ptr >= 10 &&
+ PRIV(strncmp_c8)(ptr, STRING_VERSION, 7) == 0 &&
+ ptr[7] != CHAR_RIGHT_PARENTHESIS)
+ {
+ uint32_t ge = 0;
+ int major = 0;
+ int minor = 0;
+
+ ptr += 7;
+ if (*ptr == CHAR_GREATER_THAN_SIGN)
+ {
+ ge = 1;
+ ptr++;
+ }
+
+ /* NOTE: cannot write IS_DIGIT(*(++ptr)) here because IS_DIGIT
+ references its argument twice. */
+
+ if (*ptr != CHAR_EQUALS_SIGN || (ptr++, !IS_DIGIT(*ptr)))
+ goto BAD_VERSION_CONDITION;
+
+ if (!read_number(&ptr, ptrend, -1, 1000, ERR79, &major, &errorcode))
+ goto FAILED;
+
+ if (ptr >= ptrend) goto BAD_VERSION_CONDITION;
+ if (*ptr == CHAR_DOT)
+ {
+ if (++ptr >= ptrend || !IS_DIGIT(*ptr)) goto BAD_VERSION_CONDITION;
+ minor = (*ptr++ - CHAR_0) * 10;
+ if (IS_DIGIT(*ptr)) minor += *ptr++ - CHAR_0;
+ if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+ goto BAD_VERSION_CONDITION;
+ }
+
+ *parsed_pattern++ = META_COND_VERSION;
+ *parsed_pattern++ = ge;
+ *parsed_pattern++ = major;
+ *parsed_pattern++ = minor;
+ }
+
+ /* All the remaining cases now require us to read a name. We cannot at
+ this stage distinguish ambiguous cases such as (?(R12) which might be a
+ recursion test by number or a name, because the named groups have not yet
+ all been identified. Those cases are treated as names, but given a
+ different META code. */
+
+ else
+ {
+ BOOL was_r_ampersand = FALSE;
+
+ if (*ptr == CHAR_R && ptrend - ptr > 1 && ptr[1] == CHAR_AMPERSAND)
+ {
+ terminator = CHAR_RIGHT_PARENTHESIS;
+ was_r_ampersand = TRUE;
+ ptr++;
+ }
+ else if (*ptr == CHAR_LESS_THAN_SIGN)
+ terminator = CHAR_GREATER_THAN_SIGN;
+ else if (*ptr == CHAR_APOSTROPHE)
+ terminator = CHAR_APOSTROPHE;
+ else
+ {
+ terminator = CHAR_RIGHT_PARENTHESIS;
+ ptr--; /* Point to char before name */
+ }
+ if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen,
+ &errorcode, cb)) goto FAILED;
+
+ /* Handle (?(R&name) */
+
+ if (was_r_ampersand)
+ {
+ *parsed_pattern = META_COND_RNAME;
+ ptr--; /* Back to closing parens */
+ }
+
+ /* Handle (?(name). If the name is "DEFINE" we identify it with a
+ special code. Likewise if the name consists of R followed only by
+ digits. Otherwise, handle it like a quoted name. */
+
+ else if (terminator == CHAR_RIGHT_PARENTHESIS)
+ {
+ if (namelen == 6 && PRIV(strncmp_c8)(name, STRING_DEFINE, 6) == 0)
+ *parsed_pattern = META_COND_DEFINE;
+ else
+ {
+ for (i = 1; i < (int)namelen; i++)
+ if (!IS_DIGIT(name[i])) break;
+ *parsed_pattern = (*name == CHAR_R && i >= (int)namelen)?
+ META_COND_RNUMBER : META_COND_NAME;
+ }
+ ptr--; /* Back to closing parens */
+ }
+
+ /* Handle (?('name') or (?(<name>) */
+
+ else *parsed_pattern = META_COND_NAME;
+
+ /* All these cases except DEFINE end with the name length and offset;
+ DEFINE just has an offset (for the "too many branches" error). */
+
+ if (*parsed_pattern++ != META_COND_DEFINE) *parsed_pattern++ = namelen;
+ PUTOFFSET(offset, parsed_pattern);
+ } /* End cases that read a name */
+
+ /* Check the closing parenthesis of the condition */
+
+ if (ptr >= ptrend || *ptr != CHAR_RIGHT_PARENTHESIS)
+ {
+ errorcode = ERR24;
+ goto FAILED;
+ }
+ ptr++;
+ break; /* End of condition processing */
+
+
+ /* ---- Atomic group ---- */
+
+ case CHAR_GREATER_THAN_SIGN:
+ *parsed_pattern++ = META_ATOMIC;
+ nest_depth++;
+ ptr++;
+ break;
+
+
+ /* ---- Lookahead assertions ---- */
+
+ case CHAR_EQUALS_SIGN:
+ *parsed_pattern++ = META_LOOKAHEAD;
+ ptr++;
+ goto POST_ASSERTION;
+
+ case CHAR_EXCLAMATION_MARK:
+ *parsed_pattern++ = META_LOOKAHEADNOT;
+ ptr++;
+ goto POST_ASSERTION;
+
+
+ /* ---- Lookbehind assertions ---- */
+
+ /* (?< followed by = or ! is a lookbehind assertion. Otherwise (?< is the
+ start of the name of a capturing group. */
+
+ case CHAR_LESS_THAN_SIGN:
+ if (ptrend - ptr <= 1 ||
+ (ptr[1] != CHAR_EQUALS_SIGN && ptr[1] != CHAR_EXCLAMATION_MARK))
+ {
+ terminator = CHAR_GREATER_THAN_SIGN;
+ goto DEFINE_NAME;
+ }
+ *parsed_pattern++ = (ptr[1] == CHAR_EQUALS_SIGN)?
+ META_LOOKBEHIND : META_LOOKBEHINDNOT;
+ *has_lookbehind = TRUE;
+ offset = (PCRE2_SIZE)(ptr - cb->start_pattern - 2);
+ PUTOFFSET(offset, parsed_pattern);
+ ptr += 2;
+ /* Fall through */
+
+ /* If the previous item was a condition starting (?(? an assertion,
+ optionally preceded by a callout, is expected. This is checked later on,
+ during actual compilation. However we need to identify this kind of
+ assertion in this pass because it must not be qualified. The value of
+ expect_cond_assert is set to 2 after (?(? is processed. We decrement it
+ for a callout - still leaving a positive value that identifies the
+ assertion. Multiple callouts or any other items will make it zero or
+ less, which doesn't matter because they will cause an error later. */
+
+ POST_ASSERTION:
+ nest_depth++;
+ if (prev_expect_cond_assert > 0)
+ {
+ if (top_nest == NULL) top_nest = (nest_save *)(cb->start_workspace);
+ else if (++top_nest >= end_nests)
+ {
+ errorcode = ERR84;
+ goto FAILED;
+ }
+ top_nest->nest_depth = nest_depth;
+ top_nest->flags = NSF_CONDASSERT;
+ top_nest->options = options & PARSE_TRACKED_OPTIONS;
+ }
+ break;
+
+
+ /* ---- Define a named group ---- */
+
+ /* A named group may be defined as (?'name') or (?<name>). In the latter
+ case we jump to DEFINE_NAME from the disambiguation of (?< above with the
+ terminator set to '>'. */
+
+ case CHAR_APOSTROPHE:
+ terminator = CHAR_APOSTROPHE; /* Terminator */
+
+ DEFINE_NAME:
+ if (!read_name(&ptr, ptrend, terminator, &offset, &name, &namelen,
+ &errorcode, cb)) goto FAILED;
+
+ /* We have a name for this capturing group. It is also assigned a number,
+ which is its primary means of identification. */
+
+ cb->bracount++;
+ *parsed_pattern++ = META_CAPTURE | cb->bracount;
+ nest_depth++;
+
+ /* Check not too many names */
+
+ if (cb->names_found >= MAX_NAME_COUNT)
+ {
+ errorcode = ERR49;
+ goto FAILED;
+ }
+
+ /* Adjust the entry size to accommodate the longest name found. */
+
+ if (namelen + IMM2_SIZE + 1 > cb->name_entry_size)
+ cb->name_entry_size = (uint16_t)(namelen + IMM2_SIZE + 1);
+
+ /* Scan the list to check for duplicates. For duplicate names, if the
+ number is the same, break the loop, which causes the name to be
+ discarded; otherwise, if DUPNAMES is not set, give an error.
+ If it is set, allow the name with a different number, but continue
+ scanning in case this is a duplicate with the same number. For
+ non-duplicate names, give an error if the number is duplicated. */
+
+ isdupname = FALSE;
+ ng = cb->named_groups;
+ for (i = 0; i < cb->names_found; i++, ng++)
+ {
+ if (namelen == ng->length &&
+ PRIV(strncmp)(name, ng->name, (PCRE2_SIZE)namelen) == 0)
+ {
+ if (ng->number == cb->bracount) break;
+ if ((options & PCRE2_DUPNAMES) == 0)
+ {
+ errorcode = ERR43;
+ goto FAILED;
+ }
+ isdupname = ng->isdup = TRUE; /* Mark as a duplicate */
+ cb->dupnames = TRUE; /* Duplicate names exist */
+ }
+ else if (ng->number == cb->bracount)
+ {
+ errorcode = ERR65;
+ goto FAILED;
+ }
+ }
+
+ if (i < cb->names_found) break; /* Ignore duplicate with same number */
+
+ /* Increase the list size if necessary */
+
+ if (cb->names_found >= cb->named_group_list_size)
+ {
+ uint32_t newsize = cb->named_group_list_size * 2;
+ named_group *newspace =
+ cb->cx->memctl.malloc(newsize * sizeof(named_group),
+ cb->cx->memctl.memory_data);
+ if (newspace == NULL)
+ {
+ errorcode = ERR21;
+ goto FAILED;
+ }
+
+ memcpy(newspace, cb->named_groups,
+ cb->named_group_list_size * sizeof(named_group));
+ if (cb->named_group_list_size > NAMED_GROUP_LIST_SIZE)
+ cb->cx->memctl.free((void *)cb->named_groups,
+ cb->cx->memctl.memory_data);
+ cb->named_groups = newspace;
+ cb->named_group_list_size = newsize;
+ }
+
+ /* Add this name to the list */
+
+ cb->named_groups[cb->names_found].name = name;
+ cb->named_groups[cb->names_found].length = (uint16_t)namelen;
+ cb->named_groups[cb->names_found].number = cb->bracount;
+ cb->named_groups[cb->names_found].isdup = (uint16_t)isdupname;
+ cb->names_found++;
+ break;
+ } /* End of (? switch */
+ break; /* End of ( handling */
+
+
+ /* ---- Branch terminators ---- */
+
+ /* Alternation: reset the capture count if we are in a (?| group. */
+
+ case CHAR_VERTICAL_LINE:
+ if (top_nest != NULL && top_nest->nest_depth == nest_depth &&
+ (top_nest->flags & NSF_RESET) != 0)
+ {
+ if (cb->bracount > top_nest->max_group)
+ top_nest->max_group = (uint16_t)cb->bracount;
+ cb->bracount = top_nest->reset_group;
+ }
+ *parsed_pattern++ = META_ALT;
+ break;
+
+ /* End of group; reset the capture count to the maximum if we are in a (?|
+ group and/or reset the options that are tracked during parsing. Disallow
+ quantifier for a condition that is an assertion. */
+
+ case CHAR_RIGHT_PARENTHESIS:
+ okquantifier = TRUE;
+ if (top_nest != NULL && top_nest->nest_depth == nest_depth)
+ {
+ options = (options & ~PARSE_TRACKED_OPTIONS) | top_nest->options;
+ if ((top_nest->flags & NSF_RESET) != 0 &&
+ top_nest->max_group > cb->bracount)
+ cb->bracount = top_nest->max_group;
+ if ((top_nest->flags & NSF_CONDASSERT) != 0)
+ okquantifier = FALSE;
+ if (top_nest == (nest_save *)(cb->start_workspace)) top_nest = NULL;
+ else top_nest--;
+ }
+ if (nest_depth == 0) /* Unmatched closing parenthesis */
+ {
+ errorcode = ERR22;
+ goto FAILED_BACK;
+ }
+ nest_depth--;
+ *parsed_pattern++ = META_KET;
+ break;
+ } /* End of switch on pattern character */
+ } /* End of main character scan loop */
+
+/* End of pattern reached. Check for missing ) at the end of a verb name. */
+
+if (inverbname && ptr >= ptrend)
+ {
+ errorcode = ERR60;
+ goto FAILED;
+ }
+
+/* Manage callout for the final item */
+
+PARSED_END:
+parsed_pattern = manage_callouts(ptr, &previous_callout, auto_callout,
+ parsed_pattern, cb);
+
+/* Insert trailing items for word and line matching (features provided for the
+benefit of pcre2grep). */
+
+if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_LINE) != 0)
+ {
+ *parsed_pattern++ = META_KET;
+ *parsed_pattern++ = META_DOLLAR;
+ }
+else if ((cb->cx->extra_options & PCRE2_EXTRA_MATCH_WORD) != 0)
+ {
+ *parsed_pattern++ = META_KET;
+ *parsed_pattern++ = META_ESCAPE + ESC_b;
+ }
+
+/* Terminate the parsed pattern, then return success if all groups are closed.
+Otherwise we have unclosed parentheses. */
+
+if (parsed_pattern >= parsed_pattern_end)
+ {
+ errorcode = ERR63; /* Internal error (parsed pattern overflow) */
+ goto FAILED;
+ }
+
+*parsed_pattern = META_END;
+if (nest_depth == 0) return 0;
+
+UNCLOSED_PARENTHESIS:
+errorcode = ERR14;
+
+/* Come here for all failures. */
+
+FAILED:
+cb->erroroffset = (PCRE2_SIZE)(ptr - cb->start_pattern);
+return errorcode;
+
+/* Some errors need to indicate the previous character. */
+
+FAILED_BACK:
+ptr--;
+goto FAILED;
+
+/* This failure happens several times. */
+
+BAD_VERSION_CONDITION:
+errorcode = ERR79;
+goto FAILED;
+}
+
+
+
+/*************************************************
+* Find first significant opcode *
+*************************************************/
+
+/* This is called by several functions that scan a compiled expression looking
+for a fixed first character, or an anchoring opcode etc. It skips over things
+that do not influence this. For some calls, it makes sense to skip negative
+forward and all backward assertions, and also the \b assertion; for others it
+does not.
+
+Arguments:
+ code pointer to the start of the group
+ skipassert TRUE if certain assertions are to be skipped
+
+Returns: pointer to the first significant opcode
+*/
+
+static const PCRE2_UCHAR*
+first_significant_code(PCRE2_SPTR code, BOOL skipassert)
+{
+for (;;)
+ {
+ switch ((int)*code)
+ {
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ if (!skipassert) return code;
+ do code += GET(code, 1); while (*code == OP_ALT);
+ code += PRIV(OP_lengths)[*code];
+ break;
+
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ if (!skipassert) return code;
+ /* Fall through */
+
+ case OP_CALLOUT:
+ case OP_CREF:
+ case OP_DNCREF:
+ case OP_RREF:
+ case OP_DNRREF:
+ case OP_FALSE:
+ case OP_TRUE:
+ code += PRIV(OP_lengths)[*code];
+ break;
+
+ case OP_CALLOUT_STR:
+ code += GET(code, 1 + 2*LINK_SIZE);
+ break;
+
+ case OP_SKIPZERO:
+ code += 2 + GET(code, 2) + LINK_SIZE;
+ break;
+
+ case OP_COND:
+ case OP_SCOND:
+ if (code[1+LINK_SIZE] != OP_FALSE || /* Not DEFINE */
+ code[GET(code, 1)] != OP_KET) /* More than one branch */
+ return code;
+ code += GET(code, 1) + 1 + LINK_SIZE;
+ break;
+
+ default:
+ return code;
+ }
+ }
+/* Control never reaches here */
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+* Get othercase range *
+*************************************************/
+
+/* This function is passed the start and end of a class range in UCP mode. It
+searches up the characters, looking for ranges of characters in the "other"
+case. Each call returns the next one, updating the start address. A character
+with multiple other cases is returned on its own with a special return value.
+
+Arguments:
+ cptr points to starting character value; updated
+ d end value
+ ocptr where to put start of othercase range
+ odptr where to put end of othercase range
+
+Yield: -1 when no more
+ 0 when a range is returned
+ >0 the CASESET offset for char with multiple other cases
+ in this case, ocptr contains the original
+*/
+
+static int
+get_othercase_range(uint32_t *cptr, uint32_t d, uint32_t *ocptr,
+ uint32_t *odptr)
+{
+uint32_t c, othercase, next;
+unsigned int co;
+
+/* Find the first character that has an other case. If it has multiple other
+cases, return its case offset value. */
+
+for (c = *cptr; c <= d; c++)
+ {
+ if ((co = UCD_CASESET(c)) != 0)
+ {
+ *ocptr = c++; /* Character that has the set */
+ *cptr = c; /* Rest of input range */
+ return (int)co;
+ }
+ if ((othercase = UCD_OTHERCASE(c)) != c) break;
+ }
+
+if (c > d) return -1; /* Reached end of range */
+
+/* Found a character that has a single other case. Search for the end of the
+range, which is either the end of the input range, or a character that has zero
+or more than one other cases. */
+
+*ocptr = othercase;
+next = othercase + 1;
+
+for (++c; c <= d; c++)
+ {
+ if ((co = UCD_CASESET(c)) != 0 || UCD_OTHERCASE(c) != next) break;
+ next++;
+ }
+
+*odptr = next - 1; /* End of othercase range */
+*cptr = c; /* Rest of input range */
+return 0;
+}
+#endif /* SUPPORT_UNICODE */
+
+
+
+/*************************************************
+* Add a character or range to a class (internal) *
+*************************************************/
+
+/* This function packages up the logic of adding a character or range of
+characters to a class. The character values in the arguments will be within the
+valid values for the current mode (8-bit, 16-bit, UTF, etc). This function is
+called only from within the "add to class" group of functions, some of which
+are recursive and mutually recursive. The external entry point is
+add_to_class().
+
+Arguments:
+ classbits the bit map for characters < 256
+ uchardptr points to the pointer for extra data
+ options the options word
+ cb compile data
+ start start of range character
+ end end of range character
+
+Returns: the number of < 256 characters added
+ the pointer to extra data is updated
+*/
+
+static unsigned int
+add_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+ uint32_t options, compile_block *cb, uint32_t start, uint32_t end)
+{
+uint32_t c;
+uint32_t classbits_end = (end <= 0xff ? end : 0xff);
+unsigned int n8 = 0;
+
+/* If caseless matching is required, scan the range and process alternate
+cases. In Unicode, there are 8-bit characters that have alternate cases that
+are greater than 255 and vice-versa. Sometimes we can just extend the original
+range. */
+
+if ((options & PCRE2_CASELESS) != 0)
+ {
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UTF) != 0)
+ {
+ int rc;
+ uint32_t oc, od;
+
+ options &= ~PCRE2_CASELESS; /* Remove for recursive calls */
+ c = start;
+
+ while ((rc = get_othercase_range(&c, end, &oc, &od)) >= 0)
+ {
+ /* Handle a single character that has more than one other case. */
+
+ if (rc > 0) n8 += add_list_to_class_internal(classbits, uchardptr, options, cb,
+ PRIV(ucd_caseless_sets) + rc, oc);
+
+ /* Do nothing if the other case range is within the original range. */
+
+ else if (oc >= cb->class_range_start && od <= cb->class_range_end) continue;
+
+ /* Extend the original range if there is overlap, noting that if oc < c, we
+ can't have od > end because a subrange is always shorter than the basic
+ range. Otherwise, use a recursive call to add the additional range. */
+
+ else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
+ else if (od > end && oc <= end + 1)
+ {
+ end = od; /* Extend upwards */
+ if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
+ }
+ else n8 += add_to_class_internal(classbits, uchardptr, options, cb, oc, od);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF mode */
+
+ for (c = start; c <= classbits_end; c++)
+ {
+ SETBIT(classbits, cb->fcc[c]);
+ n8++;
+ }
+ }
+
+/* Now handle the originally supplied range. Adjust the final value according
+to the bit length - this means that the same lists of (e.g.) horizontal spaces
+can be used in all cases. */
+
+if ((options & PCRE2_UTF) == 0 && end > MAX_NON_UTF_CHAR)
+ end = MAX_NON_UTF_CHAR;
+
+if (start > cb->class_range_start && end < cb->class_range_end) return n8;
+
+/* Use the bitmap for characters < 256. Otherwise use extra data.*/
+
+for (c = start; c <= classbits_end; c++)
+ {
+ /* Regardless of start, c will always be <= 255. */
+ SETBIT(classbits, c);
+ n8++;
+ }
+
+#ifdef SUPPORT_WIDE_CHARS
+if (start <= 0xff) start = 0xff + 1;
+
+if (end >= start)
+ {
+ PCRE2_UCHAR *uchardata = *uchardptr;
+
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UTF) != 0)
+ {
+ if (start < end)
+ {
+ *uchardata++ = XCL_RANGE;
+ uchardata += PRIV(ord2utf)(start, uchardata);
+ uchardata += PRIV(ord2utf)(end, uchardata);
+ }
+ else if (start == end)
+ {
+ *uchardata++ = XCL_SINGLE;
+ uchardata += PRIV(ord2utf)(start, uchardata);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Without UTF support, character values are constrained by the bit length,
+ and can only be > 256 for 16-bit and 32-bit libraries. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ {}
+#else
+ if (start < end)
+ {
+ *uchardata++ = XCL_RANGE;
+ *uchardata++ = start;
+ *uchardata++ = end;
+ }
+ else if (start == end)
+ {
+ *uchardata++ = XCL_SINGLE;
+ *uchardata++ = start;
+ }
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ *uchardptr = uchardata; /* Updata extra data pointer */
+ }
+#else /* SUPPORT_WIDE_CHARS */
+ (void)uchardptr; /* Avoid compiler warning */
+#endif /* SUPPORT_WIDE_CHARS */
+
+return n8; /* Number of 8-bit characters */
+}
+
+
+
+#ifdef SUPPORT_UNICODE
+/*************************************************
+* Add a list of characters to a class (internal) *
+*************************************************/
+
+/* This function is used for adding a list of case-equivalent characters to a
+class when in UTF mode. This function is called only from within
+add_to_class_internal(), with which it is mutually recursive.
+
+Arguments:
+ classbits the bit map for characters < 256
+ uchardptr points to the pointer for extra data
+ options the options word
+ cb contains pointers to tables etc.
+ p points to row of 32-bit values, terminated by NOTACHAR
+ except character to omit; this is used when adding lists of
+ case-equivalent characters to avoid including the one we
+ already know about
+
+Returns: the number of < 256 characters added
+ the pointer to extra data is updated
+*/
+
+static unsigned int
+add_list_to_class_internal(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+ uint32_t options, compile_block *cb, const uint32_t *p, unsigned int except)
+{
+unsigned int n8 = 0;
+while (p[0] < NOTACHAR)
+ {
+ unsigned int n = 0;
+ if (p[0] != except)
+ {
+ while(p[n+1] == p[0] + n + 1) n++;
+ n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]);
+ }
+ p += n + 1;
+ }
+return n8;
+}
+#endif
+
+
+
+/*************************************************
+* External entry point for add range to class *
+*************************************************/
+
+/* This function sets the overall range so that the internal functions can try
+to avoid duplication when handling case-independence.
+
+Arguments:
+ classbits the bit map for characters < 256
+ uchardptr points to the pointer for extra data
+ options the options word
+ cb compile data
+ start start of range character
+ end end of range character
+
+Returns: the number of < 256 characters added
+ the pointer to extra data is updated
+*/
+
+static unsigned int
+add_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+ compile_block *cb, uint32_t start, uint32_t end)
+{
+cb->class_range_start = start;
+cb->class_range_end = end;
+return add_to_class_internal(classbits, uchardptr, options, cb, start, end);
+}
+
+
+/*************************************************
+* External entry point for add list to class *
+*************************************************/
+
+/* This function is used for adding a list of horizontal or vertical whitespace
+characters to a class. The list must be in order so that ranges of characters
+can be detected and handled appropriately. This function sets the overall range
+so that the internal functions can try to avoid duplication when handling
+case-independence.
+
+Arguments:
+ classbits the bit map for characters < 256
+ uchardptr points to the pointer for extra data
+ options the options word
+ cb contains pointers to tables etc.
+ p points to row of 32-bit values, terminated by NOTACHAR
+ except character to omit; this is used when adding lists of
+ case-equivalent characters to avoid including the one we
+ already know about
+
+Returns: the number of < 256 characters added
+ the pointer to extra data is updated
+*/
+
+static unsigned int
+add_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr, uint32_t options,
+ compile_block *cb, const uint32_t *p, unsigned int except)
+{
+unsigned int n8 = 0;
+while (p[0] < NOTACHAR)
+ {
+ unsigned int n = 0;
+ if (p[0] != except)
+ {
+ while(p[n+1] == p[0] + n + 1) n++;
+ cb->class_range_start = p[0];
+ cb->class_range_end = p[n];
+ n8 += add_to_class_internal(classbits, uchardptr, options, cb, p[0], p[n]);
+ }
+ p += n + 1;
+ }
+return n8;
+}
+
+
+
+/*************************************************
+* Add characters not in a list to a class *
+*************************************************/
+
+/* This function is used for adding the complement of a list of horizontal or
+vertical whitespace to a class. The list must be in order.
+
+Arguments:
+ classbits the bit map for characters < 256
+ uchardptr points to the pointer for extra data
+ options the options word
+ cb contains pointers to tables etc.
+ p points to row of 32-bit values, terminated by NOTACHAR
+
+Returns: the number of < 256 characters added
+ the pointer to extra data is updated
+*/
+
+static unsigned int
+add_not_list_to_class(uint8_t *classbits, PCRE2_UCHAR **uchardptr,
+ uint32_t options, compile_block *cb, const uint32_t *p)
+{
+BOOL utf = (options & PCRE2_UTF) != 0;
+unsigned int n8 = 0;
+if (p[0] > 0)
+ n8 += add_to_class(classbits, uchardptr, options, cb, 0, p[0] - 1);
+while (p[0] < NOTACHAR)
+ {
+ while (p[1] == p[0] + 1) p++;
+ n8 += add_to_class(classbits, uchardptr, options, cb, p[0] + 1,
+ (p[1] == NOTACHAR) ? (utf ? 0x10ffffu : 0xffffffffu) : p[1] - 1);
+ p++;
+ }
+return n8;
+}
+
+
+
+/*************************************************
+* Find details of duplicate group names *
+*************************************************/
+
+/* This is called from compile_branch() when it needs to know the index and
+count of duplicates in the names table when processing named backreferences,
+either directly, or as conditions.
+
+Arguments:
+ name points to the name
+ length the length of the name
+ indexptr where to put the index
+ countptr where to put the count of duplicates
+ errorcodeptr where to put an error code
+ cb the compile block
+
+Returns: TRUE if OK, FALSE if not, error code set
+*/
+
+static BOOL
+find_dupname_details(PCRE2_SPTR name, uint32_t length, int *indexptr,
+ int *countptr, int *errorcodeptr, compile_block *cb)
+{
+uint32_t i, groupnumber;
+int count;
+PCRE2_UCHAR *slot = cb->name_table;
+
+/* Find the first entry in the table */
+
+for (i = 0; i < cb->names_found; i++)
+ {
+ if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) == 0 &&
+ slot[IMM2_SIZE+length] == 0) break;
+ slot += cb->name_entry_size;
+ }
+
+/* This should not occur, because this function is called only when we know we
+have duplicate names. Give an internal error. */
+
+if (i >= cb->names_found)
+ {
+ *errorcodeptr = ERR53;
+ cb->erroroffset = name - cb->start_pattern;
+ return FALSE;
+ }
+
+/* Record the index and then see how many duplicates there are, updating the
+backref map and maximum back reference as we do. */
+
+*indexptr = i;
+count = 0;
+
+for (;;)
+ {
+ count++;
+ groupnumber = GET2(slot,0);
+ cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
+ if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
+ if (++i >= cb->names_found) break;
+ slot += cb->name_entry_size;
+ if (PRIV(strncmp)(name, slot+IMM2_SIZE, length) != 0 ||
+ (slot+IMM2_SIZE)[length] != 0) break;
+ }
+
+*countptr = count;
+return TRUE;
+}
+
+
+
+/*************************************************
+* Compile one branch *
+*************************************************/
+
+/* Scan the parsed pattern, compiling it into the a vector of PCRE2_UCHAR. If
+the options are changed during the branch, the pointer is used to change the
+external options bits. This function is used during the pre-compile phase when
+we are trying to find out the amount of memory needed, as well as during the
+real compile phase. The value of lengthptr distinguishes the two phases.
+
+Arguments:
+ optionsptr pointer to the option bits
+ codeptr points to the pointer to the current code point
+ pptrptr points to the current parsed pattern pointer
+ errorcodeptr points to error code variable
+ firstcuptr place to put the first required code unit
+ firstcuflagsptr place to put the first code unit flags, or a negative number
+ reqcuptr place to put the last required code unit
+ reqcuflagsptr place to put the last required code unit flags, or a negative number
+ bcptr points to current branch chain
+ cb contains pointers to tables etc.
+ lengthptr NULL during the real compile phase
+ points to length accumulator during pre-compile phase
+
+Returns: 0 There's been an error, *errorcodeptr is non-zero
+ +1 Success, this branch must match at least one character
+ -1 Success, this branch may match an empty string
+*/
+
+static int
+compile_branch(uint32_t *optionsptr, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
+ int *errorcodeptr, uint32_t *firstcuptr, int32_t *firstcuflagsptr,
+ uint32_t *reqcuptr, int32_t *reqcuflagsptr, branch_chain *bcptr,
+ compile_block *cb, PCRE2_SIZE *lengthptr)
+{
+int bravalue = 0;
+int okreturn = -1;
+int group_return = 0;
+uint32_t repeat_min = 0, repeat_max = 0; /* To please picky compilers */
+uint32_t greedy_default, greedy_non_default;
+uint32_t repeat_type, op_type;
+uint32_t options = *optionsptr; /* May change dynamically */
+uint32_t firstcu, reqcu;
+uint32_t zeroreqcu, zerofirstcu;
+uint32_t escape;
+uint32_t *pptr = *pptrptr;
+uint32_t meta, meta_arg;
+int32_t firstcuflags, reqcuflags;
+int32_t zeroreqcuflags, zerofirstcuflags;
+int32_t req_caseopt, reqvary, tempreqvary;
+PCRE2_SIZE offset = 0;
+PCRE2_SIZE length_prevgroup = 0;
+PCRE2_UCHAR *code = *codeptr;
+PCRE2_UCHAR *last_code = code;
+PCRE2_UCHAR *orig_code = code;
+PCRE2_UCHAR *tempcode;
+PCRE2_UCHAR *previous = NULL;
+PCRE2_UCHAR op_previous;
+BOOL groupsetfirstcu = FALSE;
+BOOL matched_char = FALSE;
+BOOL previous_matched_char = FALSE;
+const uint8_t *cbits = cb->cbits;
+uint8_t classbits[32];
+
+/* We can fish out the UTF setting once and for all into a BOOL, but we must
+not do this for other options (e.g. PCRE2_EXTENDED) because they may change
+dynamically as we process the pattern. */
+
+#ifdef SUPPORT_UNICODE
+BOOL utf = (options & PCRE2_UTF) != 0;
+#else /* No UTF support */
+BOOL utf = FALSE;
+#endif
+
+/* Helper variables for OP_XCLASS opcode (for characters > 255). We define
+class_uchardata always so that it can be passed to add_to_class() always,
+though it will not be used in non-UTF 8-bit cases. This avoids having to supply
+alternative calls for the different cases. */
+
+PCRE2_UCHAR *class_uchardata;
+#ifdef SUPPORT_WIDE_CHARS
+BOOL xclass;
+PCRE2_UCHAR *class_uchardata_base;
+#endif
+
+/* Set up the default and non-default settings for greediness */
+
+greedy_default = ((options & PCRE2_UNGREEDY) != 0);
+greedy_non_default = greedy_default ^ 1;
+
+/* Initialize no first unit, no required unit. REQ_UNSET means "no char
+matching encountered yet". It gets changed to REQ_NONE if we hit something that
+matches a non-fixed first unit; reqcu just remains unset if we never find one.
+
+When we hit a repeat whose minimum is zero, we may have to adjust these values
+to take the zero repeat into account. This is implemented by setting them to
+zerofirstcu and zeroreqcu when such a repeat is encountered. The individual
+item types that can be repeated set these backoff variables appropriately. */
+
+firstcu = reqcu = zerofirstcu = zeroreqcu = 0;
+firstcuflags = reqcuflags = zerofirstcuflags = zeroreqcuflags = REQ_UNSET;
+
+/* The variable req_caseopt contains either the REQ_CASELESS value or zero,
+according to the current setting of the caseless flag. The REQ_CASELESS value
+leaves the lower 28 bit empty. It is added into the firstcu or reqcu variables
+to record the case status of the value. This is used only for ASCII characters.
+*/
+
+req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS:0;
+
+/* Switch on next META item until the end of the branch */
+
+for (;; pptr++)
+ {
+#ifdef SUPPORT_WIDE_CHARS
+ BOOL xclass_has_prop;
+#endif
+ BOOL negate_class;
+ BOOL should_flip_negation;
+ BOOL match_all_or_no_wide_chars;
+ BOOL possessive_quantifier;
+ BOOL note_group_empty;
+ int class_has_8bitchar;
+ int i;
+ uint32_t mclength;
+ uint32_t skipunits;
+ uint32_t subreqcu, subfirstcu;
+ uint32_t groupnumber;
+ uint32_t verbarglen, verbculen;
+ int32_t subreqcuflags, subfirstcuflags; /* Must be signed */
+ open_capitem *oc;
+ PCRE2_UCHAR mcbuffer[8];
+
+ /* Get next META item in the pattern and its potential argument. */
+
+ meta = META_CODE(*pptr);
+ meta_arg = META_DATA(*pptr);
+
+ /* If we are in the pre-compile phase, accumulate the length used for the
+ previous cycle of this loop, unless the next item is a quantifier. */
+
+ if (lengthptr != NULL)
+ {
+ if (code > cb->start_workspace + cb->workspace_size -
+ WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */
+ {
+ *errorcodeptr = (code >= cb->start_workspace + cb->workspace_size)?
+ ERR52 : ERR86;
+ return 0;
+ }
+
+ /* There is at least one situation where code goes backwards: this is the
+ case of a zero quantifier after a class (e.g. [ab]{0}). When the quantifier
+ is processed, the whole class is eliminated. However, it is created first,
+ so we have to allow memory for it. Therefore, don't ever reduce the length
+ at this point. */
+
+ if (code < last_code) code = last_code;
+
+ /* If the next thing is not a quantifier, we add the length of the previous
+ item into the total, and reset the code pointer to the start of the
+ workspace. Otherwise leave the previous item available to be quantified. */
+
+ if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
+ {
+ if (OFLOW_MAX - *lengthptr < (PCRE2_SIZE)(code - orig_code))
+ {
+ *errorcodeptr = ERR20; /* Integer overflow */
+ return 0;
+ }
+ *lengthptr += (PCRE2_SIZE)(code - orig_code);
+ if (*lengthptr > MAX_PATTERN_SIZE)
+ {
+ *errorcodeptr = ERR20; /* Pattern is too large */
+ return 0;
+ }
+ code = orig_code;
+ }
+
+ /* Remember where this code item starts so we can catch the "backwards"
+ case above next time round. */
+
+ last_code = code;
+ }
+
+ /* Process the next parsed pattern item. If it is not a quantifier, remember
+ where it starts so that it can be quantified when a quantifier follows.
+ Checking for the legality of quantifiers happens in parse_regex(), except for
+ a quantifier after an assertion that is a condition. */
+
+ if (meta < META_ASTERISK || meta > META_MINMAX_QUERY)
+ {
+ previous = code;
+ if (matched_char) okreturn = 1;
+ }
+
+ previous_matched_char = matched_char;
+ matched_char = FALSE;
+ note_group_empty = FALSE;
+ skipunits = 0; /* Default value for most subgroups */
+
+ switch(meta)
+ {
+ /* ===================================================================*/
+ /* The branch terminates at pattern end or | or ) */
+
+ case META_END:
+ case META_ALT:
+ case META_KET:
+ *firstcuptr = firstcu;
+ *firstcuflagsptr = firstcuflags;
+ *reqcuptr = reqcu;
+ *reqcuflagsptr = reqcuflags;
+ *codeptr = code;
+ *pptrptr = pptr;
+ return okreturn;
+
+
+ /* ===================================================================*/
+ /* Handle single-character metacharacters. In multiline mode, ^ disables
+ the setting of any following char as a first character. */
+
+ case META_CIRCUMFLEX:
+ if ((options & PCRE2_MULTILINE) != 0)
+ {
+ if (firstcuflags == REQ_UNSET)
+ zerofirstcuflags = firstcuflags = REQ_NONE;
+ *code++ = OP_CIRCM;
+ }
+ else *code++ = OP_CIRC;
+ break;
+
+ case META_DOLLAR:
+ *code++ = ((options & PCRE2_MULTILINE) != 0)? OP_DOLLM : OP_DOLL;
+ break;
+
+ /* There can never be a first char if '.' is first, whatever happens about
+ repeats. The value of reqcu doesn't change either. */
+
+ case META_DOT:
+ matched_char = TRUE;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+ *code++ = ((options & PCRE2_DOTALL) != 0)? OP_ALLANY: OP_ANY;
+ break;
+
+
+ /* ===================================================================*/
+ /* Empty character classes are allowed if PCRE2_ALLOW_EMPTY_CLASS is set.
+ Otherwise, an initial ']' is taken as a data character. When empty classes
+ are allowed, [] must always fail, so generate OP_FAIL, whereas [^] must
+ match any character, so generate OP_ALLANY. */
+
+ case META_CLASS_EMPTY:
+ case META_CLASS_EMPTY_NOT:
+ matched_char = TRUE;
+ *code++ = (meta == META_CLASS_EMPTY_NOT)? OP_ALLANY : OP_FAIL;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ break;
+
+
+ /* ===================================================================*/
+ /* Non-empty character class. If the included characters are all < 256, we
+ build a 32-byte bitmap of the permitted characters, except in the special
+ case where there is only one such character. For negated classes, we build
+ the map as usual, then invert it at the end. However, we use a different
+ opcode so that data characters > 255 can be handled correctly.
+
+ If the class contains characters outside the 0-255 range, a different
+ opcode is compiled. It may optionally have a bit map for characters < 256,
+ but those above are are explicitly listed afterwards. A flag code unit
+ tells whether the bitmap is present, and whether this is a negated class or
+ not. */
+
+ case META_CLASS_NOT:
+ case META_CLASS:
+ matched_char = TRUE;
+ negate_class = meta == META_CLASS_NOT;
+
+ /* We can optimize the case of a single character in a class by generating
+ OP_CHAR or OP_CHARI if it's positive, or OP_NOT or OP_NOTI if it's
+ negative. In the negative case there can be no first char if this item is
+ first, whatever repeat count may follow. In the case of reqcu, save the
+ previous value for reinstating. */
+
+ /* NOTE: at present this optimization is not effective if the only
+ character in a class in 32-bit, non-UCP mode has its top bit set. */
+
+ if (pptr[1] < META_END && pptr[2] == META_CLASS_END)
+ {
+#ifdef SUPPORT_UNICODE
+ uint32_t d;
+#endif
+ uint32_t c = pptr[1];
+
+ pptr += 2; /* Move on to class end */
+ if (meta == META_CLASS) /* A positive one-char class can be */
+ { /* handled as a normal literal character. */
+ meta = c; /* Set up the character */
+ goto NORMAL_CHAR_SET;
+ }
+
+ /* Handle a negative one-character class */
+
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+
+ /* For caseless UTF mode, check whether this character has more than
+ one other case. If so, generate a special OP_NOTPROP item instead of
+ OP_NOTI. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf && (options & PCRE2_CASELESS) != 0 &&
+ (d = UCD_CASESET(c)) != 0)
+ {
+ *code++ = OP_NOTPROP;
+ *code++ = PT_CLIST;
+ *code++ = d;
+ break; /* We are finished with this class */
+ }
+#endif
+ /* Char has only one other case, or UCP not available */
+
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_NOTI: OP_NOT;
+ code += PUTCHAR(c, code);
+ break; /* We are finished with this class */
+ } /* End of 1-char optimization */
+
+ /* Handle character classes that contain more than just one literal
+ character. */
+
+ /* If a non-extended class contains a negative special such as \S, we need
+ to flip the negation flag at the end, so that support for characters > 255
+ works correctly (they are all included in the class). An extended class may
+ need to insert specific matching or non-matching code for wide characters.
+ */
+
+ should_flip_negation = match_all_or_no_wide_chars = FALSE;
+
+ /* Extended class (xclass) will be used when characters > 255
+ might match. */
+
+#ifdef SUPPORT_WIDE_CHARS
+ xclass = FALSE;
+ class_uchardata = code + LINK_SIZE + 2; /* For XCLASS items */
+ class_uchardata_base = class_uchardata; /* Save the start */
+#endif
+
+ /* For optimization purposes, we track some properties of the class:
+ class_has_8bitchar will be non-zero if the class contains at least one
+ character with a code point less than 256; xclass_has_prop will be TRUE if
+ Unicode property checks are present in the class. */
+
+ class_has_8bitchar = 0;
+#ifdef SUPPORT_WIDE_CHARS
+ xclass_has_prop = FALSE;
+#endif
+
+ /* Initialize the 256-bit (32-byte) bit map to all zeros. We build the map
+ in a temporary bit of memory, in case the class contains fewer than two
+ 8-bit characters because in that case the compiled code doesn't use the bit
+ map. */
+
+ memset(classbits, 0, 32 * sizeof(uint8_t));
+
+ /* Process items until META_CLASS_END is reached. */
+
+ while ((meta = *(++pptr)) != META_CLASS_END)
+ {
+ /* Handle POSIX classes such as [:alpha:] etc. */
+
+ if (meta == META_POSIX || meta == META_POSIX_NEG)
+ {
+ BOOL local_negate = (meta == META_POSIX_NEG);
+ int posix_class = *(++pptr);
+ int taboffset, tabopt;
+ uint8_t pbits[32];
+
+ should_flip_negation = local_negate; /* Note negative special */
+
+ /* If matching is caseless, upper and lower are converted to alpha.
+ This relies on the fact that the class table starts with alpha,
+ lower, upper as the first 3 entries. */
+
+ if ((options & PCRE2_CASELESS) != 0 && posix_class <= 2)
+ posix_class = 0;
+
+ /* When PCRE2_UCP is set, some of the POSIX classes are converted to
+ different escape sequences that use Unicode properties \p or \P.
+ Others that are not available via \p or \P have to generate
+ XCL_PROP/XCL_NOTPROP directly, which is done here. */
+
+#ifdef SUPPORT_UNICODE
+ if ((options & PCRE2_UCP) != 0) switch(posix_class)
+ {
+ case PC_GRAPH:
+ case PC_PRINT:
+ case PC_PUNCT:
+ *class_uchardata++ = local_negate? XCL_NOTPROP : XCL_PROP;
+ *class_uchardata++ = (PCRE2_UCHAR)
+ ((posix_class == PC_GRAPH)? PT_PXGRAPH :
+ (posix_class == PC_PRINT)? PT_PXPRINT : PT_PXPUNCT);
+ *class_uchardata++ = 0;
+ xclass_has_prop = TRUE;
+ goto CONTINUE_CLASS;
+
+ /* For the other POSIX classes (ascii, xdigit) we are going to
+ fall through to the non-UCP case and build a bit map for
+ characters with code points less than 256. However, if we are in
+ a negated POSIX class, characters with code points greater than
+ 255 must either all match or all not match, depending on whether
+ the whole class is not or is negated. For example, for
+ [[:^ascii:]... they must all match, whereas for [^[:^xdigit:]...
+ they must not.
+
+ In the special case where there are no xclass items, this is
+ automatically handled by the use of OP_CLASS or OP_NCLASS, but an
+ explicit range is needed for OP_XCLASS. Setting a flag here
+ causes the range to be generated later when it is known that
+ OP_XCLASS is required. In the 8-bit library this is relevant only in
+ utf mode, since no wide characters can exist otherwise. */
+
+ default:
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (utf)
+#endif
+ match_all_or_no_wide_chars |= local_negate;
+ break;
+ }
+#endif /* SUPPORT_UNICODE */
+
+ /* In the non-UCP case, or when UCP makes no difference, we build the
+ bit map for the POSIX class in a chunk of local store because we may
+ be adding and subtracting from it, and we don't want to subtract bits
+ that may be in the main map already. At the end we or the result into
+ the bit map that is being built. */
+
+ posix_class *= 3;
+
+ /* Copy in the first table (always present) */
+
+ memcpy(pbits, cbits + posix_class_maps[posix_class],
+ 32 * sizeof(uint8_t));
+
+ /* If there is a second table, add or remove it as required. */
+
+ taboffset = posix_class_maps[posix_class + 1];
+ tabopt = posix_class_maps[posix_class + 2];
+
+ if (taboffset >= 0)
+ {
+ if (tabopt >= 0)
+ for (i = 0; i < 32; i++) pbits[i] |= cbits[(int)i + taboffset];
+ else
+ for (i = 0; i < 32; i++) pbits[i] &= ~cbits[(int)i + taboffset];
+ }
+
+ /* Now see if we need to remove any special characters. An option
+ value of 1 removes vertical space and 2 removes underscore. */
+
+ if (tabopt < 0) tabopt = -tabopt;
+ if (tabopt == 1) pbits[1] &= ~0x3c;
+ else if (tabopt == 2) pbits[11] &= 0x7f;
+
+ /* Add the POSIX table or its complement into the main table that is
+ being built and we are done. */
+
+ if (local_negate)
+ for (i = 0; i < 32; i++) classbits[i] |= ~pbits[i];
+ else
+ for (i = 0; i < 32; i++) classbits[i] |= pbits[i];
+
+ /* Every class contains at least one < 256 character. */
+
+ class_has_8bitchar = 1;
+ goto CONTINUE_CLASS; /* End of POSIX handling */
+ }
+
+ /* Other than POSIX classes, the only items we should encounter are
+ \d-type escapes and literal characters (possibly as ranges). */
+
+ if (meta == META_BIGVALUE)
+ {
+ meta = *(++pptr);
+ goto CLASS_LITERAL;
+ }
+
+ /* Any other non-literal must be an escape */
+
+ if (meta >= META_END)
+ {
+ if (META_CODE(meta) != META_ESCAPE)
+ {
+#ifdef DEBUG_SHOW_PARSED
+ fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x "
+ "in character class\n", meta);
+#endif
+ *errorcodeptr = ERR89; /* Internal error - unrecognized. */
+ return 0;
+ }
+ escape = META_DATA(meta);
+
+ /* Every class contains at least one < 256 character. */
+
+ class_has_8bitchar++;
+
+ switch(escape)
+ {
+ case ESC_d:
+ for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_digit];
+ break;
+
+ case ESC_D:
+ should_flip_negation = TRUE;
+ for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_digit];
+ break;
+
+ case ESC_w:
+ for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_word];
+ break;
+
+ case ESC_W:
+ should_flip_negation = TRUE;
+ for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_word];
+ break;
+
+ /* Perl 5.004 onwards omitted VT from \s, but restored it at Perl
+ 5.18. Before PCRE 8.34, we had to preserve the VT bit if it was
+ previously set by something earlier in the character class.
+ Luckily, the value of CHAR_VT is 0x0b in both ASCII and EBCDIC, so
+ we could just adjust the appropriate bit. From PCRE 8.34 we no
+ longer treat \s and \S specially. */
+
+ case ESC_s:
+ for (i = 0; i < 32; i++) classbits[i] |= cbits[i+cbit_space];
+ break;
+
+ case ESC_S:
+ should_flip_negation = TRUE;
+ for (i = 0; i < 32; i++) classbits[i] |= ~cbits[i+cbit_space];
+ break;
+
+ /* When adding the horizontal or vertical space lists to a class, or
+ their complements, disable PCRE2_CASELESS, because it justs wastes
+ time, and in the "not-x" UTF cases can create unwanted duplicates in
+ the XCLASS list (provoked by characters that have more than one other
+ case and by both cases being in the same "not-x" sublist). */
+
+ case ESC_h:
+ (void)add_list_to_class(classbits, &class_uchardata,
+ options & ~PCRE2_CASELESS, cb, PRIV(hspace_list), NOTACHAR);
+ break;
+
+ case ESC_H:
+ (void)add_not_list_to_class(classbits, &class_uchardata,
+ options & ~PCRE2_CASELESS, cb, PRIV(hspace_list));
+ break;
+
+ case ESC_v:
+ (void)add_list_to_class(classbits, &class_uchardata,
+ options & ~PCRE2_CASELESS, cb, PRIV(vspace_list), NOTACHAR);
+ break;
+
+ case ESC_V:
+ (void)add_not_list_to_class(classbits, &class_uchardata,
+ options & ~PCRE2_CASELESS, cb, PRIV(vspace_list));
+ break;
+
+ /* If Unicode is not supported, \P and \p are not allowed and are
+ faulted at parse time, so will never appear here. */
+
+#ifdef SUPPORT_UNICODE
+ case ESC_p:
+ case ESC_P:
+ {
+ uint32_t ptype = *(++pptr) >> 16;
+ uint32_t pdata = *pptr & 0xffff;
+ *class_uchardata++ = (escape == ESC_p)? XCL_PROP : XCL_NOTPROP;
+ *class_uchardata++ = ptype;
+ *class_uchardata++ = pdata;
+ xclass_has_prop = TRUE;
+ class_has_8bitchar--; /* Undo! */
+ }
+ break;
+#endif
+ }
+
+ goto CONTINUE_CLASS;
+ } /* End handling \d-type escapes */
+
+ /* A literal character may be followed by a range meta. At parse time
+ there are checks for out-of-order characters, for ranges where the two
+ characters are equal, and for hyphens that cannot indicate a range. At
+ this point, therefore, no checking is needed. */
+
+ else
+ {
+ uint32_t c, d;
+
+ CLASS_LITERAL:
+ c = d = meta;
+
+ /* Remember if \r or \n were explicitly used */
+
+ if (c == CHAR_CR || c == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
+
+ /* Process a character range */
+
+ if (pptr[1] == META_RANGE_LITERAL || pptr[1] == META_RANGE_ESCAPED)
+ {
+#ifdef EBCDIC
+ BOOL range_is_literal = (pptr[1] == META_RANGE_LITERAL);
+#endif
+ pptr += 2;
+ d = *pptr;
+ if (d == META_BIGVALUE) d = *(++pptr);
+
+ /* Remember an explicit \r or \n, and add the range to the class. */
+
+ if (d == CHAR_CR || d == CHAR_NL) cb->external_flags |= PCRE2_HASCRORLF;
+
+ /* In an EBCDIC environment, Perl treats alphabetic ranges specially
+ because there are holes in the encoding, and simply using the range
+ A-Z (for example) would include the characters in the holes. This
+ applies only to literal ranges; [\xC1-\xE9] is different to [A-Z]. */
+
+#ifdef EBCDIC
+ if (range_is_literal &&
+ (cb->ctypes[c] & ctype_letter) != 0 &&
+ (cb->ctypes[d] & ctype_letter) != 0 &&
+ (d <= CHAR_z) == (d <= CHAR_z))
+ {
+ uint32_t uc = (d <= CHAR_z)? 0 : 64;
+ uint32_t C = d - uc;
+ uint32_t D = d - uc;
+
+ if (C <= CHAR_i)
+ {
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+ ((D < CHAR_i)? D : CHAR_i) + uc);
+ C = CHAR_j;
+ }
+
+ if (C <= D && C <= CHAR_r)
+ {
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+ ((D < CHAR_r)? D : CHAR_r) + uc);
+ C = CHAR_s;
+ }
+
+ if (C <= D)
+ {
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, C + uc,
+ D + uc);
+ }
+ }
+ else
+#endif
+ /* Not an EBCDIC special range */
+
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, c, d);
+ goto CONTINUE_CLASS; /* Go get the next char in the class */
+ } /* End of range handling */
+
+
+ /* Handle a single character. */
+
+ class_has_8bitchar +=
+ add_to_class(classbits, &class_uchardata, options, cb, meta, meta);
+ }
+
+ /* Continue to the next item in the class. */
+
+ CONTINUE_CLASS:
+
+#ifdef SUPPORT_WIDE_CHARS
+ /* If any wide characters or Unicode properties have been encountered,
+ set xclass = TRUE. Then, in the pre-compile phase, accumulate the length
+ of the extra data and reset the pointer. This is so that very large
+ classes that contain a zillion wide characters or Unicode property tests
+ do not overwrite the workspace (which is on the stack). */
+
+ if (class_uchardata > class_uchardata_base)
+ {
+ xclass = TRUE;
+ if (lengthptr != NULL)
+ {
+ *lengthptr += class_uchardata - class_uchardata_base;
+ class_uchardata = class_uchardata_base;
+ }
+ }
+#endif
+
+ continue; /* Needed to avoid error when not supporting wide chars */
+ } /* End of main class-processing loop */
+
+ /* If this class is the first thing in the branch, there can be no first
+ char setting, whatever the repeat count. Any reqcu setting must remain
+ unchanged after any kind of repeat. */
+
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+
+ /* If there are characters with values > 255, or Unicode property settings
+ (\p or \P), we have to compile an extended class, with its own opcode,
+ unless there were no property settings and there was a negated special such
+ as \S in the class, and PCRE2_UCP is not set, because in that case all
+ characters > 255 are in or not in the class, so any that were explicitly
+ given as well can be ignored.
+
+ In the UCP case, if certain negated POSIX classes ([:^ascii:] or
+ [^:xdigit:]) were present in a class, we either have to match or not match
+ all wide characters (depending on whether the whole class is or is not
+ negated). This requirement is indicated by match_all_or_no_wide_chars being
+ true. We do this by including an explicit range, which works in both cases.
+ This applies only in UTF and 16-bit and 32-bit non-UTF modes, since there
+ cannot be any wide characters in 8-bit non-UTF mode.
+
+ When there *are* properties in a positive UTF-8 or any 16-bit or 32_bit
+ class where \S etc is present without PCRE2_UCP, causing an extended class
+ to be compiled, we make sure that all characters > 255 are included by
+ forcing match_all_or_no_wide_chars to be true.
+
+ If, when generating an xclass, there are no characters < 256, we can omit
+ the bitmap in the actual compiled code. */
+
+#ifdef SUPPORT_WIDE_CHARS /* Defined for 16/32 bits, or 8-bit with Unicode */
+ if (xclass && (
+#ifdef SUPPORT_UNICODE
+ (options & PCRE2_UCP) != 0 ||
+#endif
+ xclass_has_prop || !should_flip_negation))
+ {
+ if (match_all_or_no_wide_chars || (
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ utf &&
+#endif
+ should_flip_negation && !negate_class && (options & PCRE2_UCP) == 0))
+ {
+ *class_uchardata++ = XCL_RANGE;
+ if (utf) /* Will always be utf in the 8-bit library */
+ {
+ class_uchardata += PRIV(ord2utf)(0x100, class_uchardata);
+ class_uchardata += PRIV(ord2utf)(MAX_UTF_CODE_POINT, class_uchardata);
+ }
+ else /* Can only happen for the 16-bit & 32-bit libraries */
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 16
+ *class_uchardata++ = 0x100;
+ *class_uchardata++ = 0xffffu;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ *class_uchardata++ = 0x100;
+ *class_uchardata++ = 0xffffffffu;
+#endif
+ }
+ }
+ *class_uchardata++ = XCL_END; /* Marks the end of extra data */
+ *code++ = OP_XCLASS;
+ code += LINK_SIZE;
+ *code = negate_class? XCL_NOT:0;
+ if (xclass_has_prop) *code |= XCL_HASPROP;
+
+ /* If the map is required, move up the extra data to make room for it;
+ otherwise just move the code pointer to the end of the extra data. */
+
+ if (class_has_8bitchar > 0)
+ {
+ *code++ |= XCL_MAP;
+ (void)memmove(code + (32 / sizeof(PCRE2_UCHAR)), code,
+ CU2BYTES(class_uchardata - code));
+ if (negate_class && !xclass_has_prop)
+ for (i = 0; i < 32; i++) classbits[i] = ~classbits[i];
+ memcpy(code, classbits, 32);
+ code = class_uchardata + (32 / sizeof(PCRE2_UCHAR));
+ }
+ else code = class_uchardata;
+
+ /* Now fill in the complete length of the item */
+
+ PUT(previous, 1, (int)(code - previous));
+ break; /* End of class handling */
+ }
+#endif /* SUPPORT_WIDE_CHARS */
+
+ /* If there are no characters > 255, or they are all to be included or
+ excluded, set the opcode to OP_CLASS or OP_NCLASS, depending on whether the
+ whole class was negated and whether there were negative specials such as \S
+ (non-UCP) in the class. Then copy the 32-byte map into the code vector,
+ negating it if necessary. */
+
+ *code++ = (negate_class == should_flip_negation) ? OP_CLASS : OP_NCLASS;
+ if (lengthptr == NULL) /* Save time in the pre-compile phase */
+ {
+ if (negate_class)
+ for (i = 0; i < 32; i++) classbits[i] = ~classbits[i];
+ memcpy(code, classbits, 32);
+ }
+ code += 32 / sizeof(PCRE2_UCHAR);
+ break; /* End of class processing */
+
+
+ /* ===================================================================*/
+ /* Deal with (*VERB)s. */
+
+ /* Check for open captures before ACCEPT and close those that are within
+ the same assertion level, also converting ACCEPT to ASSERT_ACCEPT in an
+ assertion. In the first pass, just accumulate the length required;
+ otherwise hitting (*ACCEPT) inside many nested parentheses can cause
+ workspace overflow. Do not set firstcu after *ACCEPT. */
+
+ case META_ACCEPT:
+ cb->had_accept = TRUE;
+ for (oc = cb->open_caps;
+ oc != NULL && oc->assert_depth >= cb->assert_depth;
+ oc = oc->next)
+ {
+ if (lengthptr != NULL)
+ {
+ *lengthptr += CU2BYTES(1) + IMM2_SIZE;
+ }
+ else
+ {
+ *code++ = OP_CLOSE;
+ PUT2INC(code, 0, oc->number);
+ }
+ }
+ *code++ = (cb->assert_depth > 0)? OP_ASSERT_ACCEPT : OP_ACCEPT;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ break;
+
+ case META_PRUNE:
+ case META_SKIP:
+ cb->had_pruneorskip = TRUE;
+ /* Fall through */
+ case META_COMMIT:
+ case META_FAIL:
+ *code++ = verbops[(meta - META_MARK) >> 16];
+ break;
+
+ case META_THEN:
+ cb->external_flags |= PCRE2_HASTHEN;
+ *code++ = OP_THEN;
+ break;
+
+ /* Handle verbs with arguments. Arguments can be very long, especially in
+ 16- and 32-bit modes, and can overflow the workspace in the first pass.
+ However, the argument length is constrained to be small enough to fit in
+ one code unit. This check happens in parse_regex(). In the first pass,
+ instead of putting the argument into memory, we just update the length
+ counter and set up an empty argument. */
+
+ case META_THEN_ARG:
+ cb->external_flags |= PCRE2_HASTHEN;
+ goto VERB_ARG;
+
+ case META_PRUNE_ARG:
+ case META_SKIP_ARG:
+ cb->had_pruneorskip = TRUE;
+ /* Fall through */
+ case META_MARK:
+ case META_COMMIT_ARG:
+ VERB_ARG:
+ *code++ = verbops[(meta - META_MARK) >> 16];
+ /* The length is in characters. */
+ verbarglen = *(++pptr);
+ verbculen = 0;
+ tempcode = code++;
+ for (i = 0; i < (int)verbarglen; i++)
+ {
+ meta = *(++pptr);
+#ifdef SUPPORT_UNICODE
+ if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else
+#endif
+ {
+ mclength = 1;
+ mcbuffer[0] = meta;
+ }
+ if (lengthptr != NULL) *lengthptr += mclength; else
+ {
+ memcpy(code, mcbuffer, CU2BYTES(mclength));
+ code += mclength;
+ verbculen += mclength;
+ }
+ }
+
+ *tempcode = verbculen; /* Fill in the code unit length */
+ *code++ = 0; /* Terminating zero */
+ break;
+
+
+ /* ===================================================================*/
+ /* Handle options change. The new setting must be passed back for use in
+ subsequent branches. Reset the greedy defaults and the case value for
+ firstcu and reqcu. */
+
+ case META_OPTIONS:
+ *optionsptr = options = *(++pptr);
+ greedy_default = ((options & PCRE2_UNGREEDY) != 0);
+ greedy_non_default = greedy_default ^ 1;
+ req_caseopt = ((options & PCRE2_CASELESS) != 0)? REQ_CASELESS : 0;
+ break;
+
+
+ /* ===================================================================*/
+ /* Handle conditional subpatterns. The case of (?(Rdigits) is ambiguous
+ because it could be a numerical check on recursion, or a name check on a
+ group's being set. The pre-pass sets up META_COND_RNUMBER as a name so that
+ we can handle it either way. We first try for a name; if not found, process
+ the number. */
+
+ case META_COND_RNUMBER: /* (?(Rdigits) */
+ case META_COND_NAME: /* (?(name) or (?'name') or ?(<name>) */
+ case META_COND_RNAME: /* (?(R&name) - test for recursion */
+ bravalue = OP_COND;
+ {
+ int count, index;
+ PCRE2_SPTR name;
+ named_group *ng = cb->named_groups;
+ uint32_t length = *(++pptr);
+
+ GETPLUSOFFSET(offset, pptr);
+ name = cb->start_pattern + offset;
+
+ /* In the first pass, the names generated in the pre-pass are available,
+ but the main name table has not yet been created. Scan the list of names
+ generated in the pre-pass in order to get a number and whether or not
+ this name is duplicated. If it is not duplicated, we can handle it as a
+ numerical group. */
+
+ for (i = 0; i < cb->names_found; i++, ng++)
+ {
+ if (length == ng->length &&
+ PRIV(strncmp)(name, ng->name, length) == 0)
+ {
+ if (!ng->isdup)
+ {
+ code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF;
+ PUT2(code, 2+LINK_SIZE, ng->number);
+ if (ng->number > cb->top_backref) cb->top_backref = ng->number;
+ skipunits = 1+IMM2_SIZE;
+ goto GROUP_PROCESS_NOTE_EMPTY;
+ }
+ break; /* Found a duplicated name */
+ }
+ }
+
+ /* If the name was not found we have a bad reference, unless we are
+ dealing with R<digits>, which is treated as a recursion test by number.
+ */
+
+ if (i >= cb->names_found)
+ {
+ groupnumber = 0;
+ if (meta == META_COND_RNUMBER)
+ {
+ for (i = 1; i < (int)length; i++)
+ {
+ groupnumber = groupnumber * 10 + name[i] - CHAR_0;
+ if (groupnumber > MAX_GROUP_NUMBER)
+ {
+ *errorcodeptr = ERR61;
+ cb->erroroffset = offset + i;
+ return 0;
+ }
+ }
+ }
+
+ if (meta != META_COND_RNUMBER || groupnumber > cb->bracount)
+ {
+ *errorcodeptr = ERR15;
+ cb->erroroffset = offset;
+ return 0;
+ }
+
+ /* (?Rdigits) treated as a recursion reference by number. A value of
+ zero (which is the result of both (?R) and (?R0)) means "any", and is
+ translated into RREF_ANY (which is 0xffff). */
+
+ if (groupnumber == 0) groupnumber = RREF_ANY;
+ code[1+LINK_SIZE] = OP_RREF;
+ PUT2(code, 2+LINK_SIZE, groupnumber);
+ skipunits = 1+IMM2_SIZE;
+ goto GROUP_PROCESS_NOTE_EMPTY;
+ }
+
+ /* A duplicated name was found. Note that if an R<digits> name is found
+ (META_COND_RNUMBER), it is a reference test, not a recursion test. */
+
+ code[1+LINK_SIZE] = (meta == META_COND_RNAME)? OP_RREF : OP_CREF;
+
+ /* We have a duplicated name. In the compile pass we have to search the
+ main table in order to get the index and count values. */
+
+ count = 0; /* Values for first pass (avoids compiler warning) */
+ index = 0;
+ if (lengthptr == NULL && !find_dupname_details(name, length, &index,
+ &count, errorcodeptr, cb)) return 0;
+
+ /* Add one to the opcode to change CREF/RREF into DNCREF/DNRREF and
+ insert appropriate data values. */
+
+ code[1+LINK_SIZE]++;
+ skipunits = 1+2*IMM2_SIZE;
+ PUT2(code, 2+LINK_SIZE, index);
+ PUT2(code, 2+LINK_SIZE+IMM2_SIZE, count);
+ }
+ goto GROUP_PROCESS_NOTE_EMPTY;
+
+ /* The DEFINE condition is always false. It's internal groups may never
+ be called, so matched_char must remain false, hence the jump to
+ GROUP_PROCESS rather than GROUP_PROCESS_NOTE_EMPTY. */
+
+ case META_COND_DEFINE:
+ bravalue = OP_COND;
+ GETPLUSOFFSET(offset, pptr);
+ code[1+LINK_SIZE] = OP_DEFINE;
+ skipunits = 1;
+ goto GROUP_PROCESS;
+
+ /* Conditional test of a group's being set. */
+
+ case META_COND_NUMBER:
+ bravalue = OP_COND;
+ GETPLUSOFFSET(offset, pptr);
+ groupnumber = *(++pptr);
+ if (groupnumber > cb->bracount)
+ {
+ *errorcodeptr = ERR15;
+ cb->erroroffset = offset;
+ return 0;
+ }
+ if (groupnumber > cb->top_backref) cb->top_backref = groupnumber;
+ offset -= 2; /* Point at initial ( for too many branches error */
+ code[1+LINK_SIZE] = OP_CREF;
+ skipunits = 1+IMM2_SIZE;
+ PUT2(code, 2+LINK_SIZE, groupnumber);
+ goto GROUP_PROCESS_NOTE_EMPTY;
+
+ /* Test for the PCRE2 version. */
+
+ case META_COND_VERSION:
+ bravalue = OP_COND;
+ if (pptr[1] > 0)
+ code[1+LINK_SIZE] = ((PCRE2_MAJOR > pptr[2]) ||
+ (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR >= pptr[3]))?
+ OP_TRUE : OP_FALSE;
+ else
+ code[1+LINK_SIZE] = (PCRE2_MAJOR == pptr[2] && PCRE2_MINOR == pptr[3])?
+ OP_TRUE : OP_FALSE;
+ skipunits = 1;
+ pptr += 3;
+ goto GROUP_PROCESS_NOTE_EMPTY;
+
+ /* The condition is an assertion, possibly preceded by a callout. */
+
+ case META_COND_ASSERT:
+ bravalue = OP_COND;
+ goto GROUP_PROCESS_NOTE_EMPTY;
+
+
+ /* ===================================================================*/
+ /* Handle all kinds of nested bracketed groups. The non-capturing,
+ non-conditional cases are here; others come to GROUP_PROCESS via goto. */
+
+ case META_LOOKAHEAD:
+ bravalue = OP_ASSERT;
+ cb->assert_depth += 1;
+ goto GROUP_PROCESS;
+
+ /* Optimize (?!) to (*FAIL) unless it is quantified - which is a weird
+ thing to do, but Perl allows all assertions to be quantified, and when
+ they contain capturing parentheses there may be a potential use for
+ this feature. Not that that applies to a quantified (?!) but we allow
+ it for uniformity. */
+
+ case META_LOOKAHEADNOT:
+ if (pptr[1] == META_KET &&
+ (pptr[2] < META_ASTERISK || pptr[2] > META_MINMAX_QUERY))
+ {
+ *code++ = OP_FAIL;
+ pptr++;
+ }
+ else
+ {
+ bravalue = OP_ASSERT_NOT;
+ cb->assert_depth += 1;
+ goto GROUP_PROCESS;
+ }
+ break;
+
+ case META_LOOKBEHIND:
+ bravalue = OP_ASSERTBACK;
+ cb->assert_depth += 1;
+ goto GROUP_PROCESS;
+
+ case META_LOOKBEHINDNOT:
+ bravalue = OP_ASSERTBACK_NOT;
+ cb->assert_depth += 1;
+ goto GROUP_PROCESS;
+
+ case META_ATOMIC:
+ bravalue = OP_ONCE;
+ goto GROUP_PROCESS_NOTE_EMPTY;
+
+ case META_NOCAPTURE:
+ bravalue = OP_BRA;
+ /* Fall through */
+
+ /* Process nested bracketed regex. The nesting depth is maintained for the
+ benefit of the stackguard function. The test for too deep nesting is now
+ done in parse_regex(). Assertion and DEFINE groups come to GROUP_PROCESS;
+ others come to GROUP_PROCESS_NOTE_EMPTY, to indicate that we need to take
+ note of whether or not they may match an empty string. */
+
+ GROUP_PROCESS_NOTE_EMPTY:
+ note_group_empty = TRUE;
+
+ GROUP_PROCESS:
+ cb->parens_depth += 1;
+ *code = bravalue;
+ pptr++;
+ tempcode = code;
+ tempreqvary = cb->req_varyopt; /* Save value before group */
+ length_prevgroup = 0; /* Initialize for pre-compile phase */
+
+ if ((group_return =
+ compile_regex(
+ options, /* The option state */
+ &tempcode, /* Where to put code (updated) */
+ &pptr, /* Input pointer (updated) */
+ errorcodeptr, /* Where to put an error message */
+ skipunits, /* Skip over bracket number */
+ &subfirstcu, /* For possible first char */
+ &subfirstcuflags,
+ &subreqcu, /* For possible last char */
+ &subreqcuflags,
+ bcptr, /* Current branch chain */
+ cb, /* Compile data block */
+ (lengthptr == NULL)? NULL : /* Actual compile phase */
+ &length_prevgroup /* Pre-compile phase */
+ )) == 0)
+ return 0; /* Error */
+
+ cb->parens_depth -= 1;
+
+ /* If that was a non-conditional significant group (not an assertion, not a
+ DEFINE) that matches at least one character, then the current item matches
+ a character. Conditionals are handled below. */
+
+ if (note_group_empty && bravalue != OP_COND && group_return > 0)
+ matched_char = TRUE;
+
+ /* If we've just compiled an assertion, pop the assert depth. */
+
+ if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT)
+ cb->assert_depth -= 1;
+
+ /* At the end of compiling, code is still pointing to the start of the
+ group, while tempcode has been updated to point past the end of the group.
+ The parsed pattern pointer (pptr) is on the closing META_KET.
+
+ If this is a conditional bracket, check that there are no more than
+ two branches in the group, or just one if it's a DEFINE group. We do this
+ in the real compile phase, not in the pre-pass, where the whole group may
+ not be available. */
+
+ if (bravalue == OP_COND && lengthptr == NULL)
+ {
+ PCRE2_UCHAR *tc = code;
+ int condcount = 0;
+
+ do {
+ condcount++;
+ tc += GET(tc,1);
+ }
+ while (*tc != OP_KET);
+
+ /* A DEFINE group is never obeyed inline (the "condition" is always
+ false). It must have only one branch. Having checked this, change the
+ opcode to OP_FALSE. */
+
+ if (code[LINK_SIZE+1] == OP_DEFINE)
+ {
+ if (condcount > 1)
+ {
+ cb->erroroffset = offset;
+ *errorcodeptr = ERR54;
+ return 0;
+ }
+ code[LINK_SIZE+1] = OP_FALSE;
+ bravalue = OP_DEFINE; /* A flag to suppress char handling below */
+ }
+
+ /* A "normal" conditional group. If there is just one branch, we must not
+ make use of its firstcu or reqcu, because this is equivalent to an
+ empty second branch. Also, it may match an empty string. If there are two
+ branches, this item must match a character if the group must. */
+
+ else
+ {
+ if (condcount > 2)
+ {
+ cb->erroroffset = offset;
+ *errorcodeptr = ERR27;
+ return 0;
+ }
+ if (condcount == 1) subfirstcuflags = subreqcuflags = REQ_NONE;
+ else if (group_return > 0) matched_char = TRUE;
+ }
+ }
+
+ /* In the pre-compile phase, update the length by the length of the group,
+ less the brackets at either end. Then reduce the compiled code to just a
+ set of non-capturing brackets so that it doesn't use much memory if it is
+ duplicated by a quantifier.*/
+
+ if (lengthptr != NULL)
+ {
+ if (OFLOW_MAX - *lengthptr < length_prevgroup - 2 - 2*LINK_SIZE)
+ {
+ *errorcodeptr = ERR20;
+ return 0;
+ }
+ *lengthptr += length_prevgroup - 2 - 2*LINK_SIZE;
+ code++; /* This already contains bravalue */
+ PUTINC(code, 0, 1 + LINK_SIZE);
+ *code++ = OP_KET;
+ PUTINC(code, 0, 1 + LINK_SIZE);
+ break; /* No need to waste time with special character handling */
+ }
+
+ /* Otherwise update the main code pointer to the end of the group. */
+
+ code = tempcode;
+
+ /* For a DEFINE group, required and first character settings are not
+ relevant. */
+
+ if (bravalue == OP_DEFINE) break;
+
+ /* Handle updating of the required and first code units for other types of
+ group. Update for normal brackets of all kinds, and conditions with two
+ branches (see code above). If the bracket is followed by a quantifier with
+ zero repeat, we have to back off. Hence the definition of zeroreqcu and
+ zerofirstcu outside the main loop so that they can be accessed for the back
+ off. */
+
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ groupsetfirstcu = FALSE;
+
+ if (bravalue >= OP_ONCE) /* Not an assertion */
+ {
+ /* If we have not yet set a firstcu in this branch, take it from the
+ subpattern, remembering that it was set here so that a repeat of more
+ than one can replicate it as reqcu if necessary. If the subpattern has
+ no firstcu, set "none" for the whole branch. In both cases, a zero
+ repeat forces firstcu to "none". */
+
+ if (firstcuflags == REQ_UNSET && subfirstcuflags != REQ_UNSET)
+ {
+ if (subfirstcuflags >= 0)
+ {
+ firstcu = subfirstcu;
+ firstcuflags = subfirstcuflags;
+ groupsetfirstcu = TRUE;
+ }
+ else firstcuflags = REQ_NONE;
+ zerofirstcuflags = REQ_NONE;
+ }
+
+ /* If firstcu was previously set, convert the subpattern's firstcu
+ into reqcu if there wasn't one, using the vary flag that was in
+ existence beforehand. */
+
+ else if (subfirstcuflags >= 0 && subreqcuflags < 0)
+ {
+ subreqcu = subfirstcu;
+ subreqcuflags = subfirstcuflags | tempreqvary;
+ }
+
+ /* If the subpattern set a required code unit (or set a first code unit
+ that isn't really the first code unit - see above), set it. */
+
+ if (subreqcuflags >= 0)
+ {
+ reqcu = subreqcu;
+ reqcuflags = subreqcuflags;
+ }
+ }
+
+ /* For a forward assertion, we take the reqcu, if set, provided that the
+ group has also set a firstcu. This can be helpful if the pattern that
+ follows the assertion doesn't set a different char. For example, it's
+ useful for /(?=abcde).+/. We can't set firstcu for an assertion, however
+ because it leads to incorrect effect for patterns such as /(?=a)a.+/ when
+ the "real" "a" would then become a reqcu instead of a firstcu. This is
+ overcome by a scan at the end if there's no firstcu, looking for an
+ asserted first char. A similar effect for patterns like /(?=.*X)X$/ means
+ we must only take the reqcu when the group also set a firstcu. Otherwise,
+ in that example, 'X' ends up set for both. */
+
+ else if (bravalue == OP_ASSERT && subreqcuflags >= 0 &&
+ subfirstcuflags >= 0)
+ {
+ reqcu = subreqcu;
+ reqcuflags = subreqcuflags;
+ }
+
+ break; /* End of nested group handling */
+
+
+ /* ===================================================================*/
+ /* Handle named backreferences and recursions. */
+
+ case META_BACKREF_BYNAME:
+ case META_RECURSE_BYNAME:
+ {
+ int count, index;
+ PCRE2_SPTR name;
+ BOOL is_dupname = FALSE;
+ named_group *ng = cb->named_groups;
+ uint32_t length = *(++pptr);
+
+ GETPLUSOFFSET(offset, pptr);
+ name = cb->start_pattern + offset;
+
+ /* In the first pass, the names generated in the pre-pass are available,
+ but the main name table has not yet been created. Scan the list of names
+ generated in the pre-pass in order to get a number and whether or not
+ this name is duplicated. */
+
+ groupnumber = 0;
+ for (i = 0; i < cb->names_found; i++, ng++)
+ {
+ if (length == ng->length &&
+ PRIV(strncmp)(name, ng->name, length) == 0)
+ {
+ is_dupname = ng->isdup;
+ groupnumber = ng->number;
+
+ /* For a recursion, that's all that is needed. We can now go to
+ the code above that handles numerical recursion, applying it to
+ the first group with the given name. */
+
+ if (meta == META_RECURSE_BYNAME)
+ {
+ meta_arg = groupnumber;
+ goto HANDLE_NUMERICAL_RECURSION;
+ }
+
+ /* For a back reference, update the back reference map and the
+ maximum back reference. Then, for each group, we must check to
+ see if it is recursive, that is, it is inside the group that it
+ references. A flag is set so that the group can be made atomic.
+ */
+
+ cb->backref_map |= (groupnumber < 32)? (1u << groupnumber) : 1;
+ if (groupnumber > cb->top_backref)
+ cb->top_backref = groupnumber;
+
+ for (oc = cb->open_caps; oc != NULL; oc = oc->next)
+ {
+ if (oc->number == groupnumber)
+ {
+ oc->flag = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* If the name was not found we have a bad reference. */
+
+ if (groupnumber == 0)
+ {
+ *errorcodeptr = ERR15;
+ cb->erroroffset = offset;
+ return 0;
+ }
+
+ /* If a back reference name is not duplicated, we can handle it as
+ a numerical reference. */
+
+ if (!is_dupname)
+ {
+ meta_arg = groupnumber;
+ goto HANDLE_SINGLE_REFERENCE;
+ }
+
+ /* If a back reference name is duplicated, we generate a different
+ opcode to a numerical back reference. In the second pass we must
+ search for the index and count in the final name table. */
+
+ count = 0; /* Values for first pass (avoids compiler warning) */
+ index = 0;
+ if (lengthptr == NULL && !find_dupname_details(name, length, &index,
+ &count, errorcodeptr, cb)) return 0;
+
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_DNREFI : OP_DNREF;
+ PUT2INC(code, 0, index);
+ PUT2INC(code, 0, count);
+ }
+ break;
+
+
+ /* ===================================================================*/
+ /* Handle a numerical callout. */
+
+ case META_CALLOUT_NUMBER:
+ code[0] = OP_CALLOUT;
+ PUT(code, 1, pptr[1]); /* Offset to next pattern item */
+ PUT(code, 1 + LINK_SIZE, pptr[2]); /* Length of next pattern item */
+ code[1 + 2*LINK_SIZE] = pptr[3];
+ pptr += 3;
+ code += PRIV(OP_lengths)[OP_CALLOUT];
+ break;
+
+
+ /* ===================================================================*/
+ /* Handle a callout with a string argument. In the pre-pass we just compute
+ the length without generating anything. The length in pptr[3] includes both
+ delimiters; in the actual compile only the first one is copied, but a
+ terminating zero is added. Any doubled delimiters within the string make
+ this an overestimate, but it is not worth bothering about. */
+
+ case META_CALLOUT_STRING:
+ if (lengthptr != NULL)
+ {
+ *lengthptr += pptr[3] + (1 + 4*LINK_SIZE);
+ pptr += 3;
+ SKIPOFFSET(pptr);
+ }
+
+ /* In the real compile we can copy the string. The starting delimiter is
+ included so that the client can discover it if they want. We also pass the
+ start offset to help a script language give better error messages. */
+
+ else
+ {
+ PCRE2_SPTR pp;
+ uint32_t delimiter;
+ uint32_t length = pptr[3];
+ PCRE2_UCHAR *callout_string = code + (1 + 4*LINK_SIZE);
+
+ code[0] = OP_CALLOUT_STR;
+ PUT(code, 1, pptr[1]); /* Offset to next pattern item */
+ PUT(code, 1 + LINK_SIZE, pptr[2]); /* Length of next pattern item */
+
+ pptr += 3;
+ GETPLUSOFFSET(offset, pptr); /* Offset to string in pattern */
+ pp = cb->start_pattern + offset;
+ delimiter = *callout_string++ = *pp++;
+ if (delimiter == CHAR_LEFT_CURLY_BRACKET)
+ delimiter = CHAR_RIGHT_CURLY_BRACKET;
+ PUT(code, 1 + 3*LINK_SIZE, (int)(offset + 1)); /* One after delimiter */
+
+ /* The syntax of the pattern was checked in the parsing scan. The length
+ includes both delimiters, but we have passed the opening one just above,
+ so we reduce length before testing it. The test is for > 1 because we do
+ not want to copy the final delimiter. This also ensures that pp[1] is
+ accessible. */
+
+ while (--length > 1)
+ {
+ if (*pp == delimiter && pp[1] == delimiter)
+ {
+ *callout_string++ = delimiter;
+ pp += 2;
+ length--;
+ }
+ else *callout_string++ = *pp++;
+ }
+ *callout_string++ = CHAR_NUL;
+
+ /* Set the length of the entire item, the advance to its end. */
+
+ PUT(code, 1 + 2*LINK_SIZE, (int)(callout_string - code));
+ code = callout_string;
+ }
+ break;
+
+
+ /* ===================================================================*/
+ /* Handle repetition. The different types are all sorted out in the parsing
+ pass. */
+
+ case META_MINMAX_PLUS:
+ case META_MINMAX_QUERY:
+ case META_MINMAX:
+ repeat_min = *(++pptr);
+ repeat_max = *(++pptr);
+ goto REPEAT;
+
+ case META_ASTERISK:
+ case META_ASTERISK_PLUS:
+ case META_ASTERISK_QUERY:
+ repeat_min = 0;
+ repeat_max = REPEAT_UNLIMITED;
+ goto REPEAT;
+
+ case META_PLUS:
+ case META_PLUS_PLUS:
+ case META_PLUS_QUERY:
+ repeat_min = 1;
+ repeat_max = REPEAT_UNLIMITED;
+ goto REPEAT;
+
+ case META_QUERY:
+ case META_QUERY_PLUS:
+ case META_QUERY_QUERY:
+ repeat_min = 0;
+ repeat_max = 1;
+
+ REPEAT:
+ if (previous_matched_char && repeat_min > 0) matched_char = TRUE;
+
+ /* Remember whether this is a variable length repeat, and default to
+ single-char opcodes. */
+
+ reqvary = (repeat_min == repeat_max)? 0 : REQ_VARY;
+ op_type = 0;
+
+ /* If the repeat is {1} we can ignore it. */
+
+ if (repeat_max == 1 && repeat_min == 1) goto END_REPEAT;
+
+ /* Adjust first and required code units for a zero repeat. */
+
+ if (repeat_min == 0)
+ {
+ firstcu = zerofirstcu;
+ firstcuflags = zerofirstcuflags;
+ reqcu = zeroreqcu;
+ reqcuflags = zeroreqcuflags;
+ }
+
+ /* Note the greediness and possessiveness. */
+
+ switch (meta)
+ {
+ case META_MINMAX_PLUS:
+ case META_ASTERISK_PLUS:
+ case META_PLUS_PLUS:
+ case META_QUERY_PLUS:
+ repeat_type = 0; /* Force greedy */
+ possessive_quantifier = TRUE;
+ break;
+
+ case META_MINMAX_QUERY:
+ case META_ASTERISK_QUERY:
+ case META_PLUS_QUERY:
+ case META_QUERY_QUERY:
+ repeat_type = greedy_non_default;
+ possessive_quantifier = FALSE;
+ break;
+
+ default:
+ repeat_type = greedy_default;
+ possessive_quantifier = FALSE;
+ break;
+ }
+
+ /* Save start of previous item, in case we have to move it up in order to
+ insert something before it, and remember what it was. */
+
+ tempcode = previous;
+ op_previous = *previous;
+
+ /* Now handle repetition for the different types of item. */
+
+ switch (op_previous)
+ {
+ /* If previous was a character or negated character match, abolish the
+ item and generate a repeat item instead. If a char item has a minimum of
+ more than one, ensure that it is set in reqcu - it might not be if a
+ sequence such as x{3} is the first thing in a branch because the x will
+ have gone into firstcu instead. */
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ op_type = chartypeoffset[op_previous - OP_CHAR];
+
+ /* Deal with UTF characters that take up more than one code unit. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf && NOT_FIRSTCU(code[-1]))
+ {
+ PCRE2_UCHAR *lastchar = code - 1;
+ BACKCHAR(lastchar);
+ mclength = (uint32_t)(code - lastchar); /* Length of UTF character */
+ memcpy(mcbuffer, lastchar, CU2BYTES(mclength)); /* Save the char */
+ }
+ else
+#endif /* MAYBE_UTF_MULTI */
+
+ /* Handle the case of a single code unit - either with no UTF support, or
+ with UTF disabled, or for a single-code-unit UTF character. */
+ {
+ mcbuffer[0] = code[-1];
+ mclength = 1;
+ if (op_previous <= OP_CHARI && repeat_min > 1)
+ {
+ reqcu = mcbuffer[0];
+ reqcuflags = req_caseopt | cb->req_varyopt;
+ }
+ }
+ goto OUTPUT_SINGLE_REPEAT; /* Code shared with single character types */
+
+ /* If previous was a character class or a back reference, we put the
+ repeat stuff after it, but just skip the item if the repeat was {0,0}. */
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+#endif
+ case OP_CLASS:
+ case OP_NCLASS:
+ case OP_REF:
+ case OP_REFI:
+ case OP_DNREF:
+ case OP_DNREFI:
+
+ if (repeat_max == 0)
+ {
+ code = previous;
+ goto END_REPEAT;
+ }
+
+ if (repeat_min == 0 && repeat_max == REPEAT_UNLIMITED)
+ *code++ = OP_CRSTAR + repeat_type;
+ else if (repeat_min == 1 && repeat_max == REPEAT_UNLIMITED)
+ *code++ = OP_CRPLUS + repeat_type;
+ else if (repeat_min == 0 && repeat_max == 1)
+ *code++ = OP_CRQUERY + repeat_type;
+ else
+ {
+ *code++ = OP_CRRANGE + repeat_type;
+ PUT2INC(code, 0, repeat_min);
+ if (repeat_max == REPEAT_UNLIMITED) repeat_max = 0; /* 2-byte encoding for max */
+ PUT2INC(code, 0, repeat_max);
+ }
+ break;
+
+ /* If previous is OP_FAIL, it was generated by an empty class []
+ (PCRE2_ALLOW_EMPTY_CLASS is set). The other ways in which OP_FAIL can be
+ generated, that is by (*FAIL) or (?!), disallow a quantifier at parse
+ time. We can just ignore this repeat. */
+
+ case OP_FAIL:
+ goto END_REPEAT;
+
+ /* Prior to 10.30, repeated recursions were wrapped in OP_ONCE brackets
+ because pcre2_match() could not handle backtracking into recursively
+ called groups. Now that this backtracking is available, we no longer need
+ to do this. However, we still need to replicate recursions as we do for
+ groups so as to have independent backtracking points. We can replicate
+ for the minimum number of repeats directly. For optional repeats we now
+ wrap the recursion in OP_BRA brackets and make use of the bracket
+ repetition. */
+
+ case OP_RECURSE:
+
+ /* Generate unwrapped repeats for a non-zero minimum, except when the
+ minimum is 1 and the maximum unlimited, because that can be handled with
+ OP_BRA terminated by OP_KETRMAX/MIN. When the maximum is equal to the
+ minimum, we just need to generate the appropriate additional copies.
+ Otherwise we need to generate one more, to simulate the situation when
+ the minimum is zero. */
+
+ if (repeat_min > 0 && (repeat_min != 1 || repeat_max != REPEAT_UNLIMITED))
+ {
+ int replicate = repeat_min;
+ if (repeat_min == repeat_max) replicate--;
+
+ /* In the pre-compile phase, we don't actually do the replication. We
+ just adjust the length as if we had. Do some paranoid checks for
+ potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
+ integer type when available, otherwise double. */
+
+ if (lengthptr != NULL)
+ {
+ PCRE2_SIZE delta = replicate*(1 + LINK_SIZE);
+ if ((INT64_OR_DOUBLE)replicate*
+ (INT64_OR_DOUBLE)(1 + LINK_SIZE) >
+ (INT64_OR_DOUBLE)INT_MAX ||
+ OFLOW_MAX - *lengthptr < delta)
+ {
+ *errorcodeptr = ERR20;
+ return 0;
+ }
+ *lengthptr += delta;
+ }
+
+ else for (i = 0; i < replicate; i++)
+ {
+ memcpy(code, previous, CU2BYTES(1 + LINK_SIZE));
+ previous = code;
+ code += 1 + LINK_SIZE;
+ }
+
+ /* If the number of repeats is fixed, we are done. Otherwise, adjust
+ the counts and fall through. */
+
+ if (repeat_min == repeat_max) break;
+ if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min;
+ repeat_min = 0;
+ }
+
+ /* Wrap the recursion call in OP_BRA brackets. */
+
+ (void)memmove(previous + 1 + LINK_SIZE, previous, CU2BYTES(1 + LINK_SIZE));
+ op_previous = *previous = OP_BRA;
+ PUT(previous, 1, 2 + 2*LINK_SIZE);
+ previous[2 + 2*LINK_SIZE] = OP_KET;
+ PUT(previous, 3 + 2*LINK_SIZE, 2 + 2*LINK_SIZE);
+ code += 2 + 2 * LINK_SIZE;
+ length_prevgroup = 3 + 3*LINK_SIZE;
+ group_return = -1; /* Set "may match empty string" */
+
+ /* Now treat as a repeated OP_BRA. */
+ /* Fall through */
+
+ /* If previous was a bracket group, we may have to replicate it in
+ certain cases. Note that at this point we can encounter only the "basic"
+ bracket opcodes such as BRA and CBRA, as this is the place where they get
+ converted into the more special varieties such as BRAPOS and SBRA.
+ Originally, PCRE did not allow repetition of assertions, but now it does,
+ for Perl compatibility. */
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_BRA:
+ case OP_CBRA:
+ case OP_COND:
+ {
+ int len = (int)(code - previous);
+ PCRE2_UCHAR *bralink = NULL;
+ PCRE2_UCHAR *brazeroptr = NULL;
+
+ /* Repeating a DEFINE group (or any group where the condition is always
+ FALSE and there is only one branch) is pointless, but Perl allows the
+ syntax, so we just ignore the repeat. */
+
+ if (op_previous == OP_COND && previous[LINK_SIZE+1] == OP_FALSE &&
+ previous[GET(previous, 1)] != OP_ALT)
+ goto END_REPEAT;
+
+ /* There is no sense in actually repeating assertions. The only
+ potential use of repetition is in cases when the assertion is optional.
+ Therefore, if the minimum is greater than zero, just ignore the repeat.
+ If the maximum is not zero or one, set it to 1. */
+
+ if (op_previous < OP_ONCE) /* Assertion */
+ {
+ if (repeat_min > 0) goto END_REPEAT;
+ if (repeat_max > 1) repeat_max = 1;
+ }
+
+ /* The case of a zero minimum is special because of the need to stick
+ OP_BRAZERO in front of it, and because the group appears once in the
+ data, whereas in other cases it appears the minimum number of times. For
+ this reason, it is simplest to treat this case separately, as otherwise
+ the code gets far too messy. There are several special subcases when the
+ minimum is zero. */
+
+ if (repeat_min == 0)
+ {
+ /* If the maximum is also zero, we used to just omit the group from
+ the output altogether, like this:
+
+ ** if (repeat_max == 0)
+ ** {
+ ** code = previous;
+ ** goto END_REPEAT;
+ ** }
+
+ However, that fails when a group or a subgroup within it is
+ referenced as a subroutine from elsewhere in the pattern, so now we
+ stick in OP_SKIPZERO in front of it so that it is skipped on
+ execution. As we don't have a list of which groups are referenced, we
+ cannot do this selectively.
+
+ If the maximum is 1 or unlimited, we just have to stick in the
+ BRAZERO and do no more at this point. */
+
+ if (repeat_max <= 1 || repeat_max == REPEAT_UNLIMITED)
+ {
+ (void)memmove(previous + 1, previous, CU2BYTES(len));
+ code++;
+ if (repeat_max == 0)
+ {
+ *previous++ = OP_SKIPZERO;
+ goto END_REPEAT;
+ }
+ brazeroptr = previous; /* Save for possessive optimizing */
+ *previous++ = OP_BRAZERO + repeat_type;
+ }
+
+ /* If the maximum is greater than 1 and limited, we have to replicate
+ in a nested fashion, sticking OP_BRAZERO before each set of brackets.
+ The first one has to be handled carefully because it's the original
+ copy, which has to be moved up. The remainder can be handled by code
+ that is common with the non-zero minimum case below. We have to
+ adjust the value or repeat_max, since one less copy is required. */
+
+ else
+ {
+ int linkoffset;
+ (void)memmove(previous + 2 + LINK_SIZE, previous, CU2BYTES(len));
+ code += 2 + LINK_SIZE;
+ *previous++ = OP_BRAZERO + repeat_type;
+ *previous++ = OP_BRA;
+
+ /* We chain together the bracket link offset fields that have to be
+ filled in later when the ends of the brackets are reached. */
+
+ linkoffset = (bralink == NULL)? 0 : (int)(previous - bralink);
+ bralink = previous;
+ PUTINC(previous, 0, linkoffset);
+ }
+
+ if (repeat_max != REPEAT_UNLIMITED) repeat_max--;
+ }
+
+ /* If the minimum is greater than zero, replicate the group as many
+ times as necessary, and adjust the maximum to the number of subsequent
+ copies that we need. */
+
+ else
+ {
+ if (repeat_min > 1)
+ {
+ /* In the pre-compile phase, we don't actually do the replication.
+ We just adjust the length as if we had. Do some paranoid checks for
+ potential integer overflow. The INT64_OR_DOUBLE type is a 64-bit
+ integer type when available, otherwise double. */
+
+ if (lengthptr != NULL)
+ {
+ PCRE2_SIZE delta = (repeat_min - 1)*length_prevgroup;
+ if ((INT64_OR_DOUBLE)(repeat_min - 1)*
+ (INT64_OR_DOUBLE)length_prevgroup >
+ (INT64_OR_DOUBLE)INT_MAX ||
+ OFLOW_MAX - *lengthptr < delta)
+ {
+ *errorcodeptr = ERR20;
+ return 0;
+ }
+ *lengthptr += delta;
+ }
+
+ /* This is compiling for real. If there is a set first code unit
+ for the group, and we have not yet set a "required code unit", set
+ it. */
+
+ else
+ {
+ if (groupsetfirstcu && reqcuflags < 0)
+ {
+ reqcu = firstcu;
+ reqcuflags = firstcuflags;
+ }
+ for (i = 1; (uint32_t)i < repeat_min; i++)
+ {
+ memcpy(code, previous, CU2BYTES(len));
+ code += len;
+ }
+ }
+ }
+
+ if (repeat_max != REPEAT_UNLIMITED) repeat_max -= repeat_min;
+ }
+
+ /* This code is common to both the zero and non-zero minimum cases. If
+ the maximum is limited, it replicates the group in a nested fashion,
+ remembering the bracket starts on a stack. In the case of a zero
+ minimum, the first one was set up above. In all cases the repeat_max
+ now specifies the number of additional copies needed. Again, we must
+ remember to replicate entries on the forward reference list. */
+
+ if (repeat_max != REPEAT_UNLIMITED)
+ {
+ /* In the pre-compile phase, we don't actually do the replication. We
+ just adjust the length as if we had. For each repetition we must add
+ 1 to the length for BRAZERO and for all but the last repetition we
+ must add 2 + 2*LINKSIZE to allow for the nesting that occurs. Do some
+ paranoid checks to avoid integer overflow. The INT64_OR_DOUBLE type
+ is a 64-bit integer type when available, otherwise double. */
+
+ if (lengthptr != NULL && repeat_max > 0)
+ {
+ PCRE2_SIZE delta = repeat_max*(length_prevgroup + 1 + 2 + 2*LINK_SIZE) -
+ 2 - 2*LINK_SIZE; /* Last one doesn't nest */
+ if ((INT64_OR_DOUBLE)repeat_max *
+ (INT64_OR_DOUBLE)(length_prevgroup + 1 + 2 + 2*LINK_SIZE)
+ > (INT64_OR_DOUBLE)INT_MAX ||
+ OFLOW_MAX - *lengthptr < delta)
+ {
+ *errorcodeptr = ERR20;
+ return 0;
+ }
+ *lengthptr += delta;
+ }
+
+ /* This is compiling for real */
+
+ else for (i = repeat_max - 1; i >= 0; i--)
+ {
+ *code++ = OP_BRAZERO + repeat_type;
+
+ /* All but the final copy start a new nesting, maintaining the
+ chain of brackets outstanding. */
+
+ if (i != 0)
+ {
+ int linkoffset;
+ *code++ = OP_BRA;
+ linkoffset = (bralink == NULL)? 0 : (int)(code - bralink);
+ bralink = code;
+ PUTINC(code, 0, linkoffset);
+ }
+
+ memcpy(code, previous, CU2BYTES(len));
+ code += len;
+ }
+
+ /* Now chain through the pending brackets, and fill in their length
+ fields (which are holding the chain links pro tem). */
+
+ while (bralink != NULL)
+ {
+ int oldlinkoffset;
+ int linkoffset = (int)(code - bralink + 1);
+ PCRE2_UCHAR *bra = code - linkoffset;
+ oldlinkoffset = GET(bra, 1);
+ bralink = (oldlinkoffset == 0)? NULL : bralink - oldlinkoffset;
+ *code++ = OP_KET;
+ PUTINC(code, 0, linkoffset);
+ PUT(bra, 1, linkoffset);
+ }
+ }
+
+ /* If the maximum is unlimited, set a repeater in the final copy. For
+ ONCE brackets, that's all we need to do. However, possessively repeated
+ ONCE brackets can be converted into non-capturing brackets, as the
+ behaviour of (?:xx)++ is the same as (?>xx)++ and this saves having to
+ deal with possessive ONCEs specially.
+
+ Otherwise, when we are doing the actual compile phase, check to see
+ whether this group is one that could match an empty string. If so,
+ convert the initial operator to the S form (e.g. OP_BRA -> OP_SBRA) so
+ that runtime checking can be done. [This check is also applied to ONCE
+ groups at runtime, but in a different way.]
+
+ Then, if the quantifier was possessive and the bracket is not a
+ conditional, we convert the BRA code to the POS form, and the KET code to
+ KETRPOS. (It turns out to be convenient at runtime to detect this kind of
+ subpattern at both the start and at the end.) The use of special opcodes
+ makes it possible to reduce greatly the stack usage in pcre2_match(). If
+ the group is preceded by OP_BRAZERO, convert this to OP_BRAPOSZERO.
+
+ Then, if the minimum number of matches is 1 or 0, cancel the possessive
+ flag so that the default action below, of wrapping everything inside
+ atomic brackets, does not happen. When the minimum is greater than 1,
+ there will be earlier copies of the group, and so we still have to wrap
+ the whole thing. */
+
+ else
+ {
+ PCRE2_UCHAR *ketcode = code - 1 - LINK_SIZE;
+ PCRE2_UCHAR *bracode = ketcode - GET(ketcode, 1);
+
+ /* Convert possessive ONCE brackets to non-capturing */
+
+ if (*bracode == OP_ONCE && possessive_quantifier) *bracode = OP_BRA;
+
+ /* For non-possessive ONCE brackets, all we need to do is to
+ set the KET. */
+
+ if (*bracode == OP_ONCE) *ketcode = OP_KETRMAX + repeat_type;
+
+ /* Handle non-ONCE brackets and possessive ONCEs (which have been
+ converted to non-capturing above). */
+
+ else
+ {
+ /* In the compile phase, adjust the opcode if the group can match
+ an empty string. For a conditional group with only one branch, the
+ value of group_return will not show "could be empty", so we must
+ check that separately. */
+
+ if (lengthptr == NULL)
+ {
+ if (group_return < 0) *bracode += OP_SBRA - OP_BRA;
+ if (*bracode == OP_COND && bracode[GET(bracode,1)] != OP_ALT)
+ *bracode = OP_SCOND;
+ }
+
+ /* Handle possessive quantifiers. */
+
+ if (possessive_quantifier)
+ {
+ /* For COND brackets, we wrap the whole thing in a possessively
+ repeated non-capturing bracket, because we have not invented POS
+ versions of the COND opcodes. */
+
+ if (*bracode == OP_COND || *bracode == OP_SCOND)
+ {
+ int nlen = (int)(code - bracode);
+ (void)memmove(bracode + 1 + LINK_SIZE, bracode, CU2BYTES(nlen));
+ code += 1 + LINK_SIZE;
+ nlen += 1 + LINK_SIZE;
+ *bracode = (*bracode == OP_COND)? OP_BRAPOS : OP_SBRAPOS;
+ *code++ = OP_KETRPOS;
+ PUTINC(code, 0, nlen);
+ PUT(bracode, 1, nlen);
+ }
+
+ /* For non-COND brackets, we modify the BRA code and use KETRPOS. */
+
+ else
+ {
+ *bracode += 1; /* Switch to xxxPOS opcodes */
+ *ketcode = OP_KETRPOS;
+ }
+
+ /* If the minimum is zero, mark it as possessive, then unset the
+ possessive flag when the minimum is 0 or 1. */
+
+ if (brazeroptr != NULL) *brazeroptr = OP_BRAPOSZERO;
+ if (repeat_min < 2) possessive_quantifier = FALSE;
+ }
+
+ /* Non-possessive quantifier */
+
+ else *ketcode = OP_KETRMAX + repeat_type;
+ }
+ }
+ }
+ break;
+
+ /* If previous was a character type match (\d or similar), abolish it and
+ create a suitable repeat item. The code is shared with single-character
+ repeats by setting op_type to add a suitable offset into repeat_type.
+ Note the the Unicode property types will be present only when
+ SUPPORT_UNICODE is defined, but we don't wrap the little bits of code
+ here because it just makes it horribly messy. */
+
+ default:
+ if (op_previous >= OP_EODN) /* Not a character type - internal error */
+ {
+ *errorcodeptr = ERR10;
+ return 0;
+ }
+ else
+ {
+ int prop_type, prop_value;
+ PCRE2_UCHAR *oldcode;
+
+ op_type = OP_TYPESTAR - OP_STAR; /* Use type opcodes */
+ mclength = 0; /* Not a character */
+
+ if (op_previous == OP_PROP || op_previous == OP_NOTPROP)
+ {
+ prop_type = previous[1];
+ prop_value = previous[2];
+ }
+ else
+ {
+ /* Come here from just above with a character in mcbuffer/mclength. */
+ OUTPUT_SINGLE_REPEAT:
+ prop_type = prop_value = -1;
+ }
+
+ /* At this point, if prop_type == prop_value == -1 we either have a
+ character in mcbuffer when mclength is greater than zero, or we have
+ mclength zero, in which case there is a non-property character type in
+ op_previous. If prop_type/value are not negative, we have a property
+ character type in op_previous. */
+
+ oldcode = code; /* Save where we were */
+ code = previous; /* Usually overwrite previous item */
+
+ /* If the maximum is zero then the minimum must also be zero; Perl allows
+ this case, so we do too - by simply omitting the item altogether. */
+
+ if (repeat_max == 0) goto END_REPEAT;
+
+ /* Combine the op_type with the repeat_type */
+
+ repeat_type += op_type;
+
+ /* A minimum of zero is handled either as the special case * or ?, or as
+ an UPTO, with the maximum given. */
+
+ if (repeat_min == 0)
+ {
+ if (repeat_max == REPEAT_UNLIMITED) *code++ = OP_STAR + repeat_type;
+ else if (repeat_max == 1) *code++ = OP_QUERY + repeat_type;
+ else
+ {
+ *code++ = OP_UPTO + repeat_type;
+ PUT2INC(code, 0, repeat_max);
+ }
+ }
+
+ /* A repeat minimum of 1 is optimized into some special cases. If the
+ maximum is unlimited, we use OP_PLUS. Otherwise, the original item is
+ left in place and, if the maximum is greater than 1, we use OP_UPTO with
+ one less than the maximum. */
+
+ else if (repeat_min == 1)
+ {
+ if (repeat_max == REPEAT_UNLIMITED)
+ *code++ = OP_PLUS + repeat_type;
+ else
+ {
+ code = oldcode; /* Leave previous item in place */
+ if (repeat_max == 1) goto END_REPEAT;
+ *code++ = OP_UPTO + repeat_type;
+ PUT2INC(code, 0, repeat_max - 1);
+ }
+ }
+
+ /* The case {n,n} is just an EXACT, while the general case {n,m} is
+ handled as an EXACT followed by an UPTO or STAR or QUERY. */
+
+ else
+ {
+ *code++ = OP_EXACT + op_type; /* NB EXACT doesn't have repeat_type */
+ PUT2INC(code, 0, repeat_min);
+
+ /* Unless repeat_max equals repeat_min, fill in the data for EXACT,
+ and then generate the second opcode. For a repeated Unicode property
+ match, there are two extra values that define the required property,
+ and mclength is set zero to indicate this. */
+
+ if (repeat_max != repeat_min)
+ {
+ if (mclength > 0)
+ {
+ memcpy(code, mcbuffer, CU2BYTES(mclength));
+ code += mclength;
+ }
+ else
+ {
+ *code++ = op_previous;
+ if (prop_type >= 0)
+ {
+ *code++ = prop_type;
+ *code++ = prop_value;
+ }
+ }
+
+ /* Now set up the following opcode */
+
+ if (repeat_max == REPEAT_UNLIMITED)
+ *code++ = OP_STAR + repeat_type;
+ else
+ {
+ repeat_max -= repeat_min;
+ if (repeat_max == 1)
+ {
+ *code++ = OP_QUERY + repeat_type;
+ }
+ else
+ {
+ *code++ = OP_UPTO + repeat_type;
+ PUT2INC(code, 0, repeat_max);
+ }
+ }
+ }
+ }
+
+ /* Fill in the character or character type for the final opcode. */
+
+ if (mclength > 0)
+ {
+ memcpy(code, mcbuffer, CU2BYTES(mclength));
+ code += mclength;
+ }
+ else
+ {
+ *code++ = op_previous;
+ if (prop_type >= 0)
+ {
+ *code++ = prop_type;
+ *code++ = prop_value;
+ }
+ }
+ }
+ break;
+ } /* End of switch on different op_previous values */
+
+
+ /* If the character following a repeat is '+', possessive_quantifier is
+ TRUE. For some opcodes, there are special alternative opcodes for this
+ case. For anything else, we wrap the entire repeated item inside OP_ONCE
+ brackets. Logically, the '+' notation is just syntactic sugar, taken from
+ Sun's Java package, but the special opcodes can optimize it.
+
+ Some (but not all) possessively repeated subpatterns have already been
+ completely handled in the code just above. For them, possessive_quantifier
+ is always FALSE at this stage. Note that the repeated item starts at
+ tempcode, not at previous, which might be the first part of a string whose
+ (former) last char we repeated. */
+
+ if (possessive_quantifier)
+ {
+ int len;
+
+ /* Possessifying an EXACT quantifier has no effect, so we can ignore it.
+ However, QUERY, STAR, or UPTO may follow (for quantifiers such as {5,6},
+ {5,}, or {5,10}). We skip over an EXACT item; if the length of what
+ remains is greater than zero, there's a further opcode that can be
+ handled. If not, do nothing, leaving the EXACT alone. */
+
+ switch(*tempcode)
+ {
+ case OP_TYPEEXACT:
+ tempcode += PRIV(OP_lengths)[*tempcode] +
+ ((tempcode[1 + IMM2_SIZE] == OP_PROP
+ || tempcode[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
+ break;
+
+ /* CHAR opcodes are used for exacts whose count is 1. */
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ tempcode += PRIV(OP_lengths)[*tempcode];
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(tempcode[-1]))
+ tempcode += GET_EXTRALEN(tempcode[-1]);
+#endif
+ break;
+
+ /* For the class opcodes, the repeat operator appears at the end;
+ adjust tempcode to point to it. */
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ tempcode += 1 + 32/sizeof(PCRE2_UCHAR);
+ break;
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ tempcode += GET(tempcode, 1);
+ break;
+#endif
+ }
+
+ /* If tempcode is equal to code (which points to the end of the repeated
+ item), it means we have skipped an EXACT item but there is no following
+ QUERY, STAR, or UPTO; the value of len will be 0, and we do nothing. In
+ all other cases, tempcode will be pointing to the repeat opcode, and will
+ be less than code, so the value of len will be greater than 0. */
+
+ len = (int)(code - tempcode);
+ if (len > 0)
+ {
+ unsigned int repcode = *tempcode;
+
+ /* There is a table for possessifying opcodes, all of which are less
+ than OP_CALLOUT. A zero entry means there is no possessified version.
+ */
+
+ if (repcode < OP_CALLOUT && opcode_possessify[repcode] > 0)
+ *tempcode = opcode_possessify[repcode];
+
+ /* For opcode without a special possessified version, wrap the item in
+ ONCE brackets. */
+
+ else
+ {
+ (void)memmove(tempcode + 1 + LINK_SIZE, tempcode, CU2BYTES(len));
+ code += 1 + LINK_SIZE;
+ len += 1 + LINK_SIZE;
+ tempcode[0] = OP_ONCE;
+ *code++ = OP_KET;
+ PUTINC(code, 0, len);
+ PUT(tempcode, 1, len);
+ }
+ }
+ }
+
+ /* We set the "follows varying string" flag for subsequently encountered
+ reqcus if it isn't already set and we have just passed a varying length
+ item. */
+
+ END_REPEAT:
+ cb->req_varyopt |= reqvary;
+ break;
+
+
+ /* ===================================================================*/
+ /* Handle a 32-bit data character with a value greater than META_END. */
+
+ case META_BIGVALUE:
+ pptr++;
+ goto NORMAL_CHAR;
+
+
+ /* ===============================================================*/
+ /* Handle a back reference by number, which is the meta argument. The
+ pattern offsets for back references to group numbers less than 10 are held
+ in a special vector, to avoid using more than two parsed pattern elements
+ in 64-bit environments. We only need the offset to the first occurrence,
+ because if that doesn't fail, subsequent ones will also be OK. */
+
+ case META_BACKREF:
+ if (meta_arg < 10) offset = cb->small_ref_offset[meta_arg];
+ else GETPLUSOFFSET(offset, pptr);
+
+ if (meta_arg > cb->bracount)
+ {
+ cb->erroroffset = offset;
+ *errorcodeptr = ERR15; /* Non-existent subpattern */
+ return 0;
+ }
+
+ /* Come here from named backref handling when the reference is to a
+ single group (that is, not to a duplicated name). The back reference
+ data will have already been updated. We must disable firstcu if not
+ set, to cope with cases like (?=(\w+))\1: which would otherwise set ':'
+ later. */
+
+ HANDLE_SINGLE_REFERENCE:
+ if (firstcuflags == REQ_UNSET) zerofirstcuflags = firstcuflags = REQ_NONE;
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_REFI : OP_REF;
+ PUT2INC(code, 0, meta_arg);
+
+ /* Update the map of back references, and keep the highest one. We
+ could do this in parse_regex() for numerical back references, but not
+ for named back references, because we don't know the numbers to which
+ named back references refer. So we do it all in this function. */
+
+ cb->backref_map |= (meta_arg < 32)? (1u << meta_arg) : 1;
+ if (meta_arg > cb->top_backref) cb->top_backref = meta_arg;
+
+ /* Check to see if this back reference is recursive, that it, it
+ is inside the group that it references. A flag is set so that the
+ group can be made atomic. */
+
+ for (oc = cb->open_caps; oc != NULL; oc = oc->next)
+ {
+ if (oc->number == meta_arg)
+ {
+ oc->flag = TRUE;
+ break;
+ }
+ }
+ break;
+
+
+ /* ===============================================================*/
+ /* Handle recursion by inserting the number of the called group (which is
+ the meta argument) after OP_RECURSE. At the end of compiling the pattern is
+ scanned and these numbers are replaced by offsets within the pattern. It is
+ done like this to avoid problems with forward references and adjusting
+ offsets when groups are duplicated and moved (as discovered in previous
+ implementations). Note that a recursion does not have a set first character
+ (relevant if it is repeated, because it will then be wrapped with ONCE
+ brackets). */
+
+ case META_RECURSE:
+ GETPLUSOFFSET(offset, pptr);
+ if (meta_arg > cb->bracount)
+ {
+ cb->erroroffset = offset;
+ *errorcodeptr = ERR15; /* Non-existent subpattern */
+ return 0;
+ }
+ HANDLE_NUMERICAL_RECURSION:
+ *code = OP_RECURSE;
+ PUT(code, 1, meta_arg);
+ code += 1 + LINK_SIZE;
+ groupsetfirstcu = FALSE;
+ cb->had_recurse = TRUE;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ break;
+
+
+ /* ===============================================================*/
+ /* Handle capturing parentheses; the number is the meta argument. */
+
+ case META_CAPTURE:
+ bravalue = OP_CBRA;
+ skipunits = IMM2_SIZE;
+ PUT2(code, 1+LINK_SIZE, meta_arg);
+ cb->lastcapture = meta_arg;
+ goto GROUP_PROCESS_NOTE_EMPTY;
+
+
+ /* ===============================================================*/
+ /* Handle escape sequence items. For ones like \d, the ESC_values are
+ arranged to be the same as the corresponding OP_values in the default case
+ when PCRE2_UCP is not set (which is the only case in which they will appear
+ here).
+
+ Note: \Q and \E are never seen here, as they were dealt with in
+ parse_pattern(). Neither are numerical back references or recursions, which
+ were turned into META_BACKREF or META_RECURSE items, respectively. \k and
+ \g, when followed by names, are turned into META_BACKREF_BYNAME or
+ META_RECURSE_BYNAME. */
+
+ case META_ESCAPE:
+
+ /* We can test for escape sequences that consume a character because their
+ values lie between ESC_b and ESC_Z; this may have to change if any new ones
+ are ever created. For these sequences, we disable the setting of a first
+ character if it hasn't already been set. */
+
+ if (meta_arg > ESC_b && meta_arg < ESC_Z)
+ {
+ matched_char = TRUE;
+ if (firstcuflags == REQ_UNSET) firstcuflags = REQ_NONE;
+ }
+
+ /* Set values to reset to if this is followed by a zero repeat. */
+
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+
+ /* If Unicode is not supported, \P and \p are not allowed and are
+ faulted at parse time, so will never appear here. */
+
+#ifdef SUPPORT_UNICODE
+ if (meta_arg == ESC_P || meta_arg == ESC_p)
+ {
+ uint32_t ptype = *(++pptr) >> 16;
+ uint32_t pdata = *pptr & 0xffff;
+ *code++ = (meta_arg == ESC_p)? OP_PROP : OP_NOTPROP;
+ *code++ = ptype;
+ *code++ = pdata;
+ break; /* End META_ESCAPE */
+ }
+#endif
+
+ /* For the rest (including \X when Unicode is supported - if not it's
+ faulted at parse time), the OP value is the escape value when PCRE2_UCP is
+ not set; if it is set, these escapes do not show up here because they are
+ converted into Unicode property tests in parse_regex(). Note that \b and \B
+ do a one-character lookbehind, and \A also behaves as if it does. */
+
+ if (meta_arg == ESC_C) cb->external_flags |= PCRE2_HASBKC; /* Record */
+ if ((meta_arg == ESC_b || meta_arg == ESC_B || meta_arg == ESC_A) &&
+ cb->max_lookbehind == 0)
+ cb->max_lookbehind = 1;
+
+ /* In non-UTF mode, and for both 32-bit modes, we turn \C into OP_ALLANY
+ instead of OP_ANYBYTE so that it works in DFA mode and in lookbehinds. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ *code++ = (meta_arg == ESC_C)? OP_ALLANY : meta_arg;
+#else
+ *code++ = (!utf && meta_arg == ESC_C)? OP_ALLANY : meta_arg;
+#endif
+ break; /* End META_ESCAPE */
+
+
+ /* ===================================================================*/
+ /* Handle an unrecognized meta value. A parsed pattern value less than
+ META_END is a literal. Otherwise we have a problem. */
+
+ default:
+ if (meta >= META_END)
+ {
+#ifdef DEBUG_SHOW_PARSED
+ fprintf(stderr, "** Unrecognized parsed pattern item 0x%.8x\n", *pptr);
+#endif
+ *errorcodeptr = ERR89; /* Internal error - unrecognized. */
+ return 0;
+ }
+
+ /* Handle a literal character. We come here by goto in the case of a
+ 32-bit, non-UTF character whose value is greater than META_END. */
+
+ NORMAL_CHAR:
+ meta = *pptr; /* Get the full 32 bits */
+ NORMAL_CHAR_SET: /* Character is already in meta */
+ matched_char = TRUE;
+
+ /* For caseless UTF mode, check whether this character has more than one
+ other case. If so, generate a special OP_PROP item instead of OP_CHARI. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf && (options & PCRE2_CASELESS) != 0)
+ {
+ uint32_t caseset = UCD_CASESET(meta);
+ if (caseset != 0)
+ {
+ *code++ = OP_PROP;
+ *code++ = PT_CLIST;
+ *code++ = caseset;
+ if (firstcuflags == REQ_UNSET)
+ firstcuflags = zerofirstcuflags = REQ_NONE;
+ break; /* End handling this meta item */
+ }
+ }
+#endif
+
+ /* Caseful matches, or not one of the multicase characters. Get the
+ character's code units into mcbuffer, with the length in mclength. When not
+ in UTF mode, the length is always 1. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf) mclength = PRIV(ord2utf)(meta, mcbuffer); else
+#endif
+ {
+ mclength = 1;
+ mcbuffer[0] = meta;
+ }
+
+ /* Generate the appropriate code */
+
+ *code++ = ((options & PCRE2_CASELESS) != 0)? OP_CHARI : OP_CHAR;
+ memcpy(code, mcbuffer, CU2BYTES(mclength));
+ code += mclength;
+
+ /* Remember if \r or \n were seen */
+
+ if (mcbuffer[0] == CHAR_CR || mcbuffer[0] == CHAR_NL)
+ cb->external_flags |= PCRE2_HASCRORLF;
+
+ /* Set the first and required code units appropriately. If no previous
+ first code unit, set it from this character, but revert to none on a zero
+ repeat. Otherwise, leave the firstcu value alone, and don't change it on
+ a zero repeat. */
+
+ if (firstcuflags == REQ_UNSET)
+ {
+ zerofirstcuflags = REQ_NONE;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+
+ /* If the character is more than one code unit long, we can set firstcu
+ only if it is not to be matched caselessly. */
+
+ if (mclength == 1 || req_caseopt == 0)
+ {
+ firstcu = mcbuffer[0];
+ firstcuflags = req_caseopt;
+ if (mclength != 1)
+ {
+ reqcu = code[-1];
+ reqcuflags = cb->req_varyopt;
+ }
+ }
+ else firstcuflags = reqcuflags = REQ_NONE;
+ }
+
+ /* firstcu was previously set; we can set reqcu only if the length is
+ 1 or the matching is caseful. */
+
+ else
+ {
+ zerofirstcu = firstcu;
+ zerofirstcuflags = firstcuflags;
+ zeroreqcu = reqcu;
+ zeroreqcuflags = reqcuflags;
+ if (mclength == 1 || req_caseopt == 0)
+ {
+ reqcu = code[-1];
+ reqcuflags = req_caseopt | cb->req_varyopt;
+ }
+ }
+ break; /* End default meta handling */
+ } /* End of big switch */
+ } /* End of big loop */
+
+/* Control never reaches here. */
+}
+
+
+
+/*************************************************
+* Compile regex: a sequence of alternatives *
+*************************************************/
+
+/* On entry, pptr is pointing past the bracket meta, but on return it points to
+the closing bracket or META_END. The code variable is pointing at the code unit
+into which the BRA operator has been stored. This function is used during the
+pre-compile phase when we are trying to find out the amount of memory needed,
+as well as during the real compile phase. The value of lengthptr distinguishes
+the two phases.
+
+Arguments:
+ options option bits, including any changes for this subpattern
+ codeptr -> the address of the current code pointer
+ pptrptr -> the address of the current parsed pattern pointer
+ errorcodeptr -> pointer to error code variable
+ skipunits skip this many code units at start (for brackets and OP_COND)
+ firstcuptr place to put the first required code unit
+ firstcuflagsptr place to put the first code unit flags, or a negative number
+ reqcuptr place to put the last required code unit
+ reqcuflagsptr place to put the last required code unit flags, or a negative number
+ bcptr pointer to the chain of currently open branches
+ cb points to the data block with tables pointers etc.
+ lengthptr NULL during the real compile phase
+ points to length accumulator during pre-compile phase
+
+Returns: 0 There has been an error
+ +1 Success, this group must match at least one character
+ -1 Success, this group may match an empty string
+*/
+
+static int
+compile_regex(uint32_t options, PCRE2_UCHAR **codeptr, uint32_t **pptrptr,
+ int *errorcodeptr, uint32_t skipunits, uint32_t *firstcuptr,
+ int32_t *firstcuflagsptr, uint32_t *reqcuptr,int32_t *reqcuflagsptr,
+ branch_chain *bcptr, compile_block *cb, PCRE2_SIZE *lengthptr)
+{
+PCRE2_UCHAR *code = *codeptr;
+PCRE2_UCHAR *last_branch = code;
+PCRE2_UCHAR *start_bracket = code;
+BOOL lookbehind;
+open_capitem capitem;
+int capnumber = 0;
+int okreturn = 1;
+uint32_t *pptr = *pptrptr;
+uint32_t firstcu, reqcu;
+uint32_t lookbehindlength;
+int32_t firstcuflags, reqcuflags;
+uint32_t branchfirstcu, branchreqcu;
+int32_t branchfirstcuflags, branchreqcuflags;
+PCRE2_SIZE length;
+branch_chain bc;
+
+/* If set, call the external function that checks for stack availability. */
+
+if (cb->cx->stack_guard != NULL &&
+ cb->cx->stack_guard(cb->parens_depth, cb->cx->stack_guard_data))
+ {
+ *errorcodeptr= ERR33;
+ return 0;
+ }
+
+/* Miscellaneous initialization */
+
+bc.outer = bcptr;
+bc.current_branch = code;
+
+firstcu = reqcu = 0;
+firstcuflags = reqcuflags = REQ_UNSET;
+
+/* Accumulate the length for use in the pre-compile phase. Start with the
+length of the BRA and KET and any extra code units that are required at the
+beginning. We accumulate in a local variable to save frequent testing of
+lengthptr for NULL. We cannot do this by looking at the value of 'code' at the
+start and end of each alternative, because compiled items are discarded during
+the pre-compile phase so that the workspace is not exceeded. */
+
+length = 2 + 2*LINK_SIZE + skipunits;
+
+/* Remember if this is a lookbehind assertion, and if it is, save its length
+and skip over the pattern offset. */
+
+lookbehind = *code == OP_ASSERTBACK || *code == OP_ASSERTBACK_NOT;
+if (lookbehind)
+ {
+ lookbehindlength = META_DATA(pptr[-1]);
+ pptr += SIZEOFFSET;
+ }
+else lookbehindlength = 0;
+
+/* If this is a capturing subpattern, add to the chain of open capturing items
+so that we can detect them if (*ACCEPT) is encountered. Note that only OP_CBRA
+need be tested here; changing this opcode to one of its variants, e.g.
+OP_SCBRAPOS, happens later, after the group has been compiled. */
+
+if (*code == OP_CBRA)
+ {
+ capnumber = GET2(code, 1 + LINK_SIZE);
+ capitem.number = capnumber;
+ capitem.next = cb->open_caps;
+ capitem.flag = FALSE;
+ capitem.assert_depth = cb->assert_depth;
+ cb->open_caps = &capitem;
+ }
+
+/* Offset is set zero to mark that this bracket is still open */
+
+PUT(code, 1, 0);
+code += 1 + LINK_SIZE + skipunits;
+
+/* Loop for each alternative branch */
+
+for (;;)
+ {
+ int branch_return;
+
+ /* Insert OP_REVERSE if this is as lookbehind assertion. */
+
+ if (lookbehind && lookbehindlength > 0)
+ {
+ *code++ = OP_REVERSE;
+ PUTINC(code, 0, lookbehindlength);
+ length += 1 + LINK_SIZE;
+ }
+
+ /* Now compile the branch; in the pre-compile phase its length gets added
+ into the length. */
+
+ if ((branch_return =
+ compile_branch(&options, &code, &pptr, errorcodeptr, &branchfirstcu,
+ &branchfirstcuflags, &branchreqcu, &branchreqcuflags, &bc,
+ cb, (lengthptr == NULL)? NULL : &length)) == 0)
+ return 0;
+
+ /* If a branch can match an empty string, so can the whole group. */
+
+ if (branch_return < 0) okreturn = -1;
+
+ /* In the real compile phase, there is some post-processing to be done. */
+
+ if (lengthptr == NULL)
+ {
+ /* If this is the first branch, the firstcu and reqcu values for the
+ branch become the values for the regex. */
+
+ if (*last_branch != OP_ALT)
+ {
+ firstcu = branchfirstcu;
+ firstcuflags = branchfirstcuflags;
+ reqcu = branchreqcu;
+ reqcuflags = branchreqcuflags;
+ }
+
+ /* If this is not the first branch, the first char and reqcu have to
+ match the values from all the previous branches, except that if the
+ previous value for reqcu didn't have REQ_VARY set, it can still match,
+ and we set REQ_VARY for the regex. */
+
+ else
+ {
+ /* If we previously had a firstcu, but it doesn't match the new branch,
+ we have to abandon the firstcu for the regex, but if there was
+ previously no reqcu, it takes on the value of the old firstcu. */
+
+ if (firstcuflags != branchfirstcuflags || firstcu != branchfirstcu)
+ {
+ if (firstcuflags >= 0)
+ {
+ if (reqcuflags < 0)
+ {
+ reqcu = firstcu;
+ reqcuflags = firstcuflags;
+ }
+ }
+ firstcuflags = REQ_NONE;
+ }
+
+ /* If we (now or from before) have no firstcu, a firstcu from the
+ branch becomes a reqcu if there isn't a branch reqcu. */
+
+ if (firstcuflags < 0 && branchfirstcuflags >= 0 &&
+ branchreqcuflags < 0)
+ {
+ branchreqcu = branchfirstcu;
+ branchreqcuflags = branchfirstcuflags;
+ }
+
+ /* Now ensure that the reqcus match */
+
+ if (((reqcuflags & ~REQ_VARY) != (branchreqcuflags & ~REQ_VARY)) ||
+ reqcu != branchreqcu)
+ reqcuflags = REQ_NONE;
+ else
+ {
+ reqcu = branchreqcu;
+ reqcuflags |= branchreqcuflags; /* To "or" REQ_VARY */
+ }
+ }
+ }
+
+ /* Handle reaching the end of the expression, either ')' or end of pattern.
+ In the real compile phase, go back through the alternative branches and
+ reverse the chain of offsets, with the field in the BRA item now becoming an
+ offset to the first alternative. If there are no alternatives, it points to
+ the end of the group. The length in the terminating ket is always the length
+ of the whole bracketed item. Return leaving the pointer at the terminating
+ char. */
+
+ if (META_CODE(*pptr) != META_ALT)
+ {
+ if (lengthptr == NULL)
+ {
+ PCRE2_SIZE branch_length = code - last_branch;
+ do
+ {
+ PCRE2_SIZE prev_length = GET(last_branch, 1);
+ PUT(last_branch, 1, branch_length);
+ branch_length = prev_length;
+ last_branch -= branch_length;
+ }
+ while (branch_length > 0);
+ }
+
+ /* Fill in the ket */
+
+ *code = OP_KET;
+ PUT(code, 1, (int)(code - start_bracket));
+ code += 1 + LINK_SIZE;
+
+ /* If it was a capturing subpattern, check to see if it contained any
+ recursive back references. If so, we must wrap it in atomic brackets. In
+ any event, remove the block from the chain. */
+
+ if (capnumber > 0)
+ {
+ if (cb->open_caps->flag)
+ {
+ (void)memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
+ CU2BYTES(code - start_bracket));
+ *start_bracket = OP_ONCE;
+ code += 1 + LINK_SIZE;
+ PUT(start_bracket, 1, (int)(code - start_bracket));
+ *code = OP_KET;
+ PUT(code, 1, (int)(code - start_bracket));
+ code += 1 + LINK_SIZE;
+ length += 2 + 2*LINK_SIZE;
+ }
+ cb->open_caps = cb->open_caps->next;
+ }
+
+ /* Set values to pass back */
+
+ *codeptr = code;
+ *pptrptr = pptr;
+ *firstcuptr = firstcu;
+ *firstcuflagsptr = firstcuflags;
+ *reqcuptr = reqcu;
+ *reqcuflagsptr = reqcuflags;
+ if (lengthptr != NULL)
+ {
+ if (OFLOW_MAX - *lengthptr < length)
+ {
+ *errorcodeptr = ERR20;
+ return 0;
+ }
+ *lengthptr += length;
+ }
+ return okreturn;
+ }
+
+ /* Another branch follows. In the pre-compile phase, we can move the code
+ pointer back to where it was for the start of the first branch. (That is,
+ pretend that each branch is the only one.)
+
+ In the real compile phase, insert an ALT node. Its length field points back
+ to the previous branch while the bracket remains open. At the end the chain
+ is reversed. It's done like this so that the start of the bracket has a
+ zero offset until it is closed, making it possible to detect recursion. */
+
+ if (lengthptr != NULL)
+ {
+ code = *codeptr + 1 + LINK_SIZE + skipunits;
+ length += 1 + LINK_SIZE;
+ }
+ else
+ {
+ *code = OP_ALT;
+ PUT(code, 1, (int)(code - last_branch));
+ bc.current_branch = last_branch = code;
+ code += 1 + LINK_SIZE;
+ }
+
+ /* Set the lookbehind length (if not in a lookbehind the value will be zero)
+ and then advance past the vertical bar. */
+
+ lookbehindlength = META_DATA(*pptr);
+ pptr++;
+ }
+/* Control never reaches here */
+}
+
+
+
+/*************************************************
+* Check for anchored pattern *
+*************************************************/
+
+/* Try to find out if this is an anchored regular expression. Consider each
+alternative branch. If they all start with OP_SOD or OP_CIRC, or with a bracket
+all of whose alternatives start with OP_SOD or OP_CIRC (recurse ad lib), then
+it's anchored. However, if this is a multiline pattern, then only OP_SOD will
+be found, because ^ generates OP_CIRCM in that mode.
+
+We can also consider a regex to be anchored if OP_SOM starts all its branches.
+This is the code for \G, which means "match at start of match position, taking
+into account the match offset".
+
+A branch is also implicitly anchored if it starts with .* and DOTALL is set,
+because that will try the rest of the pattern at all possible matching points,
+so there is no point trying again.... er ....
+
+.... except when the .* appears inside capturing parentheses, and there is a
+subsequent back reference to those parentheses. We haven't enough information
+to catch that case precisely.
+
+At first, the best we could do was to detect when .* was in capturing brackets
+and the highest back reference was greater than or equal to that level.
+However, by keeping a bitmap of the first 31 back references, we can catch some
+of the more common cases more precisely.
+
+... A second exception is when the .* appears inside an atomic group, because
+this prevents the number of characters it matches from being adjusted.
+
+Arguments:
+ code points to start of the compiled pattern
+ bracket_map a bitmap of which brackets we are inside while testing; this
+ handles up to substring 31; after that we just have to take
+ the less precise approach
+ cb points to the compile data block
+ atomcount atomic group level
+ inassert TRUE if in an assertion
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+is_anchored(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb,
+ int atomcount, BOOL inassert)
+{
+do {
+ PCRE2_SPTR scode = first_significant_code(
+ code + PRIV(OP_lengths)[*code], FALSE);
+ int op = *scode;
+
+ /* Non-capturing brackets */
+
+ if (op == OP_BRA || op == OP_BRAPOS ||
+ op == OP_SBRA || op == OP_SBRAPOS)
+ {
+ if (!is_anchored(scode, bracket_map, cb, atomcount, inassert))
+ return FALSE;
+ }
+
+ /* Capturing brackets */
+
+ else if (op == OP_CBRA || op == OP_CBRAPOS ||
+ op == OP_SCBRA || op == OP_SCBRAPOS)
+ {
+ int n = GET2(scode, 1+LINK_SIZE);
+ int new_map = bracket_map | ((n < 32)? (1u << n) : 1);
+ if (!is_anchored(scode, new_map, cb, atomcount, inassert)) return FALSE;
+ }
+
+ /* Positive forward assertion */
+
+ else if (op == OP_ASSERT)
+ {
+ if (!is_anchored(scode, bracket_map, cb, atomcount, TRUE)) return FALSE;
+ }
+
+ /* Condition. If there is no second branch, it can't be anchored. */
+
+ else if (op == OP_COND || op == OP_SCOND)
+ {
+ if (scode[GET(scode,1)] != OP_ALT) return FALSE;
+ if (!is_anchored(scode, bracket_map, cb, atomcount, inassert))
+ return FALSE;
+ }
+
+ /* Atomic groups */
+
+ else if (op == OP_ONCE)
+ {
+ if (!is_anchored(scode, bracket_map, cb, atomcount + 1, inassert))
+ return FALSE;
+ }
+
+ /* .* is not anchored unless DOTALL is set (which generates OP_ALLANY) and
+ it isn't in brackets that are or may be referenced or inside an atomic
+ group or an assertion. Also the pattern must not contain *PRUNE or *SKIP,
+ because these break the feature. Consider, for example, /(?s).*?(*PRUNE)b/
+ with the subject "aab", which matches "b", i.e. not at the start of a line.
+ There is also an option that disables auto-anchoring. */
+
+ else if ((op == OP_TYPESTAR || op == OP_TYPEMINSTAR ||
+ op == OP_TYPEPOSSTAR))
+ {
+ if (scode[1] != OP_ALLANY || (bracket_map & cb->backref_map) != 0 ||
+ atomcount > 0 || cb->had_pruneorskip || inassert ||
+ (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)
+ return FALSE;
+ }
+
+ /* Check for explicit anchoring */
+
+ else if (op != OP_SOD && op != OP_SOM && op != OP_CIRC) return FALSE;
+
+ code += GET(code, 1);
+ }
+while (*code == OP_ALT); /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+* Check for starting with ^ or .* *
+*************************************************/
+
+/* This is called to find out if every branch starts with ^ or .* so that
+"first char" processing can be done to speed things up in multiline
+matching and for non-DOTALL patterns that start with .* (which must start at
+the beginning or after \n). As in the case of is_anchored() (see above), we
+have to take account of back references to capturing brackets that contain .*
+because in that case we can't make the assumption. Also, the appearance of .*
+inside atomic brackets or in an assertion, or in a pattern that contains *PRUNE
+or *SKIP does not count, because once again the assumption no longer holds.
+
+Arguments:
+ code points to start of the compiled pattern or a group
+ bracket_map a bitmap of which brackets we are inside while testing; this
+ handles up to substring 31; after that we just have to take
+ the less precise approach
+ cb points to the compile data
+ atomcount atomic group level
+ inassert TRUE if in an assertion
+
+Returns: TRUE or FALSE
+*/
+
+static BOOL
+is_startline(PCRE2_SPTR code, unsigned int bracket_map, compile_block *cb,
+ int atomcount, BOOL inassert)
+{
+do {
+ PCRE2_SPTR scode = first_significant_code(
+ code + PRIV(OP_lengths)[*code], FALSE);
+ int op = *scode;
+
+ /* If we are at the start of a conditional assertion group, *both* the
+ conditional assertion *and* what follows the condition must satisfy the test
+ for start of line. Other kinds of condition fail. Note that there may be an
+ auto-callout at the start of a condition. */
+
+ if (op == OP_COND)
+ {
+ scode += 1 + LINK_SIZE;
+
+ if (*scode == OP_CALLOUT) scode += PRIV(OP_lengths)[OP_CALLOUT];
+ else if (*scode == OP_CALLOUT_STR) scode += GET(scode, 1 + 2*LINK_SIZE);
+
+ switch (*scode)
+ {
+ case OP_CREF:
+ case OP_DNCREF:
+ case OP_RREF:
+ case OP_DNRREF:
+ case OP_FAIL:
+ case OP_FALSE:
+ case OP_TRUE:
+ return FALSE;
+
+ default: /* Assertion */
+ if (!is_startline(scode, bracket_map, cb, atomcount, TRUE)) return FALSE;
+ do scode += GET(scode, 1); while (*scode == OP_ALT);
+ scode += 1 + LINK_SIZE;
+ break;
+ }
+ scode = first_significant_code(scode, FALSE);
+ op = *scode;
+ }
+
+ /* Non-capturing brackets */
+
+ if (op == OP_BRA || op == OP_BRAPOS ||
+ op == OP_SBRA || op == OP_SBRAPOS)
+ {
+ if (!is_startline(scode, bracket_map, cb, atomcount, inassert))
+ return FALSE;
+ }
+
+ /* Capturing brackets */
+
+ else if (op == OP_CBRA || op == OP_CBRAPOS ||
+ op == OP_SCBRA || op == OP_SCBRAPOS)
+ {
+ int n = GET2(scode, 1+LINK_SIZE);
+ int new_map = bracket_map | ((n < 32)? (1u << n) : 1);
+ if (!is_startline(scode, new_map, cb, atomcount, inassert)) return FALSE;
+ }
+
+ /* Positive forward assertions */
+
+ else if (op == OP_ASSERT)
+ {
+ if (!is_startline(scode, bracket_map, cb, atomcount, TRUE))
+ return FALSE;
+ }
+
+ /* Atomic brackets */
+
+ else if (op == OP_ONCE)
+ {
+ if (!is_startline(scode, bracket_map, cb, atomcount + 1, inassert))
+ return FALSE;
+ }
+
+ /* .* means "start at start or after \n" if it isn't in atomic brackets or
+ brackets that may be referenced or an assertion, and as long as the pattern
+ does not contain *PRUNE or *SKIP, because these break the feature. Consider,
+ for example, /.*?a(*PRUNE)b/ with the subject "aab", which matches "ab",
+ i.e. not at the start of a line. There is also an option that disables this
+ optimization. */
+
+ else if (op == OP_TYPESTAR || op == OP_TYPEMINSTAR || op == OP_TYPEPOSSTAR)
+ {
+ if (scode[1] != OP_ANY || (bracket_map & cb->backref_map) != 0 ||
+ atomcount > 0 || cb->had_pruneorskip || inassert ||
+ (cb->external_options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)
+ return FALSE;
+ }
+
+ /* Check for explicit circumflex; anything else gives a FALSE result. Note
+ in particular that this includes atomic brackets OP_ONCE because the number
+ of characters matched by .* cannot be adjusted inside them. */
+
+ else if (op != OP_CIRC && op != OP_CIRCM) return FALSE;
+
+ /* Move on to the next alternative */
+
+ code += GET(code, 1);
+ }
+while (*code == OP_ALT); /* Loop for each alternative */
+return TRUE;
+}
+
+
+
+/*************************************************
+* Scan compiled regex for recursion reference *
+*************************************************/
+
+/* This function scans through a compiled pattern until it finds an instance of
+OP_RECURSE.
+
+Arguments:
+ code points to start of expression
+ utf TRUE in UTF mode
+
+Returns: pointer to the opcode for OP_RECURSE, or NULL if not found
+*/
+
+static PCRE2_SPTR
+find_recurse(PCRE2_SPTR code, BOOL utf)
+{
+for (;;)
+ {
+ PCRE2_UCHAR c = *code;
+ if (c == OP_END) return NULL;
+ if (c == OP_RECURSE) return code;
+
+ /* XCLASS is used for classes that cannot be represented just by a bit map.
+ This includes negated single high-valued characters. CALLOUT_STR is used for
+ callouts with string arguments. In both cases the length in the table is
+ zero; the actual length is stored in the compiled code. */
+
+ if (c == OP_XCLASS) code += GET(code, 1);
+ else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
+
+ /* Otherwise, we can get the item's length from the table, except that for
+ repeated character types, we have to test for \p and \P, which have an extra
+ two code units of parameters, and for MARK/PRUNE/SKIP/THEN with an argument,
+ we must add in its length. */
+
+ else
+ {
+ switch(c)
+ {
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+ break;
+
+ case OP_TYPEPOSUPTO:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ code += 2;
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ code += code[1];
+ break;
+ }
+
+ /* Add in the fixed length from the table */
+
+ code += PRIV(OP_lengths)[c];
+
+ /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may
+ be followed by a multi-unit character. The length in the table is a
+ minimum, so we have to arrange to skip the extra units. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf) switch(c)
+ {
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ case OP_UPTO:
+ case OP_UPTOI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ case OP_STAR:
+ case OP_STARI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+ break;
+ }
+#else
+ (void)(utf); /* Keep compiler happy by referencing function argument */
+#endif /* MAYBE_UTF_MULTI */
+ }
+ }
+}
+
+
+
+/*************************************************
+* Check for asserted fixed first code unit *
+*************************************************/
+
+/* During compilation, the "first code unit" settings from forward assertions
+are discarded, because they can cause conflicts with actual literals that
+follow. However, if we end up without a first code unit setting for an
+unanchored pattern, it is worth scanning the regex to see if there is an
+initial asserted first code unit. If all branches start with the same asserted
+code unit, or with a non-conditional bracket all of whose alternatives start
+with the same asserted code unit (recurse ad lib), then we return that code
+unit, with the flags set to zero or REQ_CASELESS; otherwise return zero with
+REQ_NONE in the flags.
+
+Arguments:
+ code points to start of compiled pattern
+ flags points to the first code unit flags
+ inassert non-zero if in an assertion
+
+Returns: the fixed first code unit, or 0 with REQ_NONE in flags
+*/
+
+static uint32_t
+find_firstassertedcu(PCRE2_SPTR code, int32_t *flags, uint32_t inassert)
+{
+uint32_t c = 0;
+int cflags = REQ_NONE;
+
+*flags = REQ_NONE;
+do {
+ uint32_t d;
+ int dflags;
+ int xl = (*code == OP_CBRA || *code == OP_SCBRA ||
+ *code == OP_CBRAPOS || *code == OP_SCBRAPOS)? IMM2_SIZE:0;
+ PCRE2_SPTR scode = first_significant_code(code + 1+LINK_SIZE + xl, TRUE);
+ PCRE2_UCHAR op = *scode;
+
+ switch(op)
+ {
+ default:
+ return 0;
+
+ case OP_BRA:
+ case OP_BRAPOS:
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_ASSERT:
+ case OP_ONCE:
+ d = find_firstassertedcu(scode, &dflags, inassert + ((op==OP_ASSERT)?1:0));
+ if (dflags < 0)
+ return 0;
+ if (cflags < 0) { c = d; cflags = dflags; }
+ else if (c != d || cflags != dflags) return 0;
+ break;
+
+ case OP_EXACT:
+ scode += IMM2_SIZE;
+ /* Fall through */
+
+ case OP_CHAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ if (inassert == 0) return 0;
+ if (cflags < 0) { c = scode[1]; cflags = 0; }
+ else if (c != scode[1]) return 0;
+ break;
+
+ case OP_EXACTI:
+ scode += IMM2_SIZE;
+ /* Fall through */
+
+ case OP_CHARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ if (inassert == 0) return 0;
+ if (cflags < 0) { c = scode[1]; cflags = REQ_CASELESS; }
+ else if (c != scode[1]) return 0;
+ break;
+ }
+
+ code += GET(code, 1);
+ }
+while (*code == OP_ALT);
+
+*flags = cflags;
+return c;
+}
+
+
+
+/*************************************************
+* Add an entry to the name/number table *
+*************************************************/
+
+/* This function is called between compiling passes to add an entry to the
+name/number table, maintaining alphabetical order. Checking for permitted
+and forbidden duplicates has already been done.
+
+Arguments:
+ cb the compile data block
+ name the name to add
+ length the length of the name
+ groupno the group number
+ tablecount the count of names in the table so far
+
+Returns: nothing
+*/
+
+static void
+add_name_to_table(compile_block *cb, PCRE2_SPTR name, int length,
+ unsigned int groupno, uint32_t tablecount)
+{
+uint32_t i;
+PCRE2_UCHAR *slot = cb->name_table;
+
+for (i = 0; i < tablecount; i++)
+ {
+ int crc = memcmp(name, slot+IMM2_SIZE, CU2BYTES(length));
+ if (crc == 0 && slot[IMM2_SIZE+length] != 0)
+ crc = -1; /* Current name is a substring */
+
+ /* Make space in the table and break the loop for an earlier name. For a
+ duplicate or later name, carry on. We do this for duplicates so that in the
+ simple case (when ?(| is not used) they are in order of their numbers. In all
+ cases they are in the order in which they appear in the pattern. */
+
+ if (crc < 0)
+ {
+ (void)memmove(slot + cb->name_entry_size, slot,
+ CU2BYTES((tablecount - i) * cb->name_entry_size));
+ break;
+ }
+
+ /* Continue the loop for a later or duplicate name */
+
+ slot += cb->name_entry_size;
+ }
+
+PUT2(slot, 0, groupno);
+memcpy(slot + IMM2_SIZE, name, CU2BYTES(length));
+
+/* Add a terminating zero and fill the rest of the slot with zeroes so that
+the memory is all initialized. Otherwise valgrind moans about uninitialized
+memory when saving serialized compiled patterns. */
+
+memset(slot + IMM2_SIZE + length, 0,
+ CU2BYTES(cb->name_entry_size - length - IMM2_SIZE));
+}
+
+
+
+/*************************************************
+* Skip in parsed pattern *
+*************************************************/
+
+/* This function is called to skip parts of the parsed pattern when finding the
+length of a lookbehind branch. It is called after (*ACCEPT) and (*FAIL) to find
+the end of the branch, it is called to skip over an internal lookaround, and it
+is also called to skip to the end of a class, during which it will never
+encounter nested groups (but there's no need to have special code for that).
+
+When called to find the end of a branch or group, pptr must point to the first
+meta code inside the branch, not the branch-starting code. In other cases it
+can point to the item that causes the function to be called.
+
+Arguments:
+ pptr current pointer to skip from
+ skiptype PSKIP_CLASS when skipping to end of class
+ PSKIP_ALT when META_ALT ends the skip
+ PSKIP_KET when only META_KET ends the skip
+
+Returns: new value of pptr
+ NULL if META_END is reached - should never occur
+ or for an unknown meta value - likewise
+*/
+
+static uint32_t *
+parsed_skip(uint32_t *pptr, uint32_t skiptype)
+{
+uint32_t nestlevel = 0;
+
+for (;; pptr++)
+ {
+ uint32_t meta = META_CODE(*pptr);
+
+ switch(meta)
+ {
+ default: /* Just skip over most items */
+ if (meta < META_END) continue; /* Literal */
+ break;
+
+ /* This should never occur. */
+
+ case META_END:
+ return NULL;
+
+ /* The data for these items is variable in length. */
+
+ case META_BACKREF: /* Offset is present only if group >= 10 */
+ if (META_DATA(*pptr) >= 10) pptr += SIZEOFFSET;
+ break;
+
+ case META_ESCAPE: /* A few escapes are followed by data items. */
+ switch (META_DATA(*pptr))
+ {
+ case ESC_P:
+ case ESC_p:
+ pptr += 1;
+ break;
+
+ case ESC_g:
+ case ESC_k:
+ pptr += 1 + SIZEOFFSET;
+ break;
+ }
+ break;
+
+ case META_MARK: /* Add the length of the name. */
+ case META_COMMIT_ARG:
+ case META_PRUNE_ARG:
+ case META_SKIP_ARG:
+ case META_THEN_ARG:
+ pptr += pptr[1];
+ break;
+
+ /* These are the "active" items in this loop. */
+
+ case META_CLASS_END:
+ if (skiptype == PSKIP_CLASS) return pptr;
+ break;
+
+ case META_ATOMIC:
+ case META_CAPTURE:
+ case META_COND_ASSERT:
+ case META_COND_DEFINE:
+ case META_COND_NAME:
+ case META_COND_NUMBER:
+ case META_COND_RNAME:
+ case META_COND_RNUMBER:
+ case META_COND_VERSION:
+ case META_LOOKAHEAD:
+ case META_LOOKAHEADNOT:
+ case META_LOOKBEHIND:
+ case META_LOOKBEHINDNOT:
+ case META_NOCAPTURE:
+ nestlevel++;
+ break;
+
+ case META_ALT:
+ if (nestlevel == 0 && skiptype == PSKIP_ALT) return pptr;
+ break;
+
+ case META_KET:
+ if (nestlevel == 0) return pptr;
+ nestlevel--;
+ break;
+ }
+
+ /* The extra data item length for each meta is in a table. */
+
+ meta = (meta >> 16) & 0x7fff;
+ if (meta >= sizeof(meta_extra_lengths)) return NULL;
+ pptr += meta_extra_lengths[meta];
+ }
+/* Control never reaches here */
+return pptr;
+}
+
+
+
+/*************************************************
+* Find length of a parsed group *
+*************************************************/
+
+/* This is called for nested groups within a branch of a lookbehind whose
+length is being computed. If all the branches in the nested group have the same
+length, that is OK. On entry, the pointer must be at the first element after
+the group initializing code. On exit it points to OP_KET. Caching is used to
+improve processing speed when the same capturing group occurs many times.
+
+Arguments:
+ pptrptr pointer to pointer in the parsed pattern
+ isinline FALSE if a reference or recursion; TRUE for inline group
+ errcodeptr pointer to the errorcode
+ lcptr pointer to the loop counter
+ group number of captured group or -1 for a non-capturing group
+ recurses chain of recurse_check to catch mutual recursion
+ cb pointer to the compile data
+
+Returns: the group length or a negative number
+*/
+
+static int
+get_grouplength(uint32_t **pptrptr, BOOL isinline, int *errcodeptr, int *lcptr,
+ int group, parsed_recurse_check *recurses, compile_block *cb)
+{
+int branchlength;
+int grouplength = -1;
+
+/* The cache can be used only if there is no possibility of there being two
+groups with the same number. We do not need to set the end pointer for a group
+that is being processed as a back reference or recursion, but we must do so for
+an inline group. */
+
+if (group > 0 && (cb->external_flags & PCRE2_DUPCAPUSED) == 0)
+ {
+ uint32_t groupinfo = cb->groupinfo[group];
+ if ((groupinfo & GI_NOT_FIXED_LENGTH) != 0) return -1;
+ if ((groupinfo & GI_SET_FIXED_LENGTH) != 0)
+ {
+ if (isinline) *pptrptr = parsed_skip(*pptrptr, PSKIP_KET);
+ return groupinfo & GI_FIXED_LENGTH_MASK;
+ }
+ }
+
+/* Scan the group. In this case we find the end pointer of necessity. */
+
+for(;;)
+ {
+ branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+ if (branchlength < 0) goto ISNOTFIXED;
+ if (grouplength == -1) grouplength = branchlength;
+ else if (grouplength != branchlength) goto ISNOTFIXED;
+ if (**pptrptr == META_KET) break;
+ *pptrptr += 1; /* Skip META_ALT */
+ }
+
+if (group > 0)
+ cb->groupinfo[group] |= (uint32_t)(GI_SET_FIXED_LENGTH | grouplength);
+return grouplength;
+
+ISNOTFIXED:
+if (group > 0) cb->groupinfo[group] |= GI_NOT_FIXED_LENGTH;
+return -1;
+}
+
+
+
+/*************************************************
+* Find length of a parsed branch *
+*************************************************/
+
+/* Return a fixed length for a branch in a lookbehind, giving an error if the
+length is not fixed. If any lookbehinds are encountered on the way, they get
+their length set. On entry, *pptrptr points to the first element inside the
+branch. On exit it is set to point to the ALT or KET.
+
+Arguments:
+ pptrptr pointer to pointer in the parsed pattern
+ errcodeptr pointer to error code
+ lcptr pointer to loop counter
+ recurses chain of recurse_check to catch mutual recursion
+ cb pointer to compile block
+
+Returns: the length, or a negative value on error
+*/
+
+static int
+get_branchlength(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+ parsed_recurse_check *recurses, compile_block *cb)
+{
+int branchlength = 0;
+int grouplength;
+uint32_t lastitemlength = 0;
+uint32_t *pptr = *pptrptr;
+PCRE2_SIZE offset;
+parsed_recurse_check this_recurse;
+
+/* A large and/or complex regex can take too long to process. This can happen
+more often when (?| groups are present in the pattern because their length
+cannot be cached. */
+
+if ((*lcptr)++ > 2000)
+ {
+ *errcodeptr = ERR35; /* Lookbehind is too complicated */
+ return -1;
+ }
+
+/* Scan the branch, accumulating the length. */
+
+for (;; pptr++)
+ {
+ parsed_recurse_check *r;
+ uint32_t *gptr, *gptrend;
+ uint32_t escape;
+ uint32_t group = 0;
+ uint32_t itemlength = 0;
+
+ if (*pptr < META_END)
+ {
+ itemlength = 1;
+ }
+
+ else switch (META_CODE(*pptr))
+ {
+ case META_KET:
+ case META_ALT:
+ goto EXIT;
+
+ /* (*ACCEPT) and (*FAIL) terminate the branch, but we must skip to the
+ actual termination. */
+
+ case META_ACCEPT:
+ case META_FAIL:
+ pptr = parsed_skip(pptr, PSKIP_ALT);
+ if (pptr == NULL) goto PARSED_SKIP_FAILED;
+ goto EXIT;
+
+ case META_MARK:
+ case META_COMMIT_ARG:
+ case META_PRUNE_ARG:
+ case META_SKIP_ARG:
+ case META_THEN_ARG:
+ pptr += pptr[1] + 1;
+ break;
+
+ case META_CIRCUMFLEX:
+ case META_COMMIT:
+ case META_DOLLAR:
+ case META_PRUNE:
+ case META_SKIP:
+ case META_THEN:
+ break;
+
+ case META_OPTIONS:
+ pptr += 1;
+ break;
+
+ case META_BIGVALUE:
+ itemlength = 1;
+ pptr += 1;
+ break;
+
+ case META_CLASS:
+ case META_CLASS_NOT:
+ itemlength = 1;
+ pptr = parsed_skip(pptr, PSKIP_CLASS);
+ if (pptr == NULL) goto PARSED_SKIP_FAILED;
+ break;
+
+ case META_CLASS_EMPTY_NOT:
+ case META_DOT:
+ itemlength = 1;
+ break;
+
+ case META_CALLOUT_NUMBER:
+ pptr += 3;
+ break;
+
+ case META_CALLOUT_STRING:
+ pptr += 3 + SIZEOFFSET;
+ break;
+
+ /* Only some escapes consume a character. Of those, \R and \X are never
+ allowed because they might match more than character. \C is allowed only in
+ 32-bit and non-UTF 8/16-bit modes. */
+
+ case META_ESCAPE:
+ escape = META_DATA(*pptr);
+ if (escape == ESC_R || escape == ESC_X) return -1;
+ if (escape > ESC_b && escape < ESC_Z)
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ if ((cb->external_options & PCRE2_UTF) != 0 && escape == ESC_C)
+ {
+ *errcodeptr = ERR36;
+ return -1;
+ }
+#endif
+ itemlength = 1;
+ if (escape == ESC_p || escape == ESC_P) pptr++; /* Skip prop data */
+ }
+ break;
+
+ /* Lookaheads can be ignored, but we must start the skip inside the group
+ so that it isn't treated as a group within the branch. */
+
+ case META_LOOKAHEAD:
+ case META_LOOKAHEADNOT:
+ pptr = parsed_skip(pptr + 1, PSKIP_KET);
+ if (pptr == NULL) goto PARSED_SKIP_FAILED;
+
+ /* Also ignore any qualifiers that follow a lookahead assertion. */
+
+ switch (pptr[1])
+ {
+ case META_ASTERISK:
+ case META_ASTERISK_PLUS:
+ case META_ASTERISK_QUERY:
+ case META_PLUS:
+ case META_PLUS_PLUS:
+ case META_PLUS_QUERY:
+ case META_QUERY:
+ case META_QUERY_PLUS:
+ case META_QUERY_QUERY:
+ pptr++;
+ break;
+
+ case META_MINMAX:
+ case META_MINMAX_PLUS:
+ case META_MINMAX_QUERY:
+ pptr += 3;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ /* Lookbehinds can be ignored, but must themselves be checked. */
+
+ case META_LOOKBEHIND:
+ case META_LOOKBEHINDNOT:
+ if (!set_lookbehind_lengths(&pptr, errcodeptr, lcptr, recurses, cb))
+ return -1;
+ break;
+
+ /* Back references and recursions are handled by very similar code. At this
+ stage, the names generated in the parsing pass are available, but the main
+ name table has not yet been created. So for the named varieties, scan the
+ list of names in order to get the number of the first one in the pattern,
+ and whether or not this name is duplicated. */
+
+ case META_BACKREF_BYNAME:
+ if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0)
+ goto ISNOTFIXED;
+ /* Fall through */
+
+ case META_RECURSE_BYNAME:
+ {
+ int i;
+ PCRE2_SPTR name;
+ BOOL is_dupname = FALSE;
+ named_group *ng = cb->named_groups;
+ uint32_t meta_code = META_CODE(*pptr);
+ uint32_t length = *(++pptr);
+
+ GETPLUSOFFSET(offset, pptr);
+ name = cb->start_pattern + offset;
+ for (i = 0; i < cb->names_found; i++, ng++)
+ {
+ if (length == ng->length && PRIV(strncmp)(name, ng->name, length) == 0)
+ {
+ group = ng->number;
+ is_dupname = ng->isdup;
+ break;
+ }
+ }
+
+ if (group == 0)
+ {
+ *errcodeptr = ERR15; /* Non-existent subpattern */
+ cb->erroroffset = offset;
+ return -1;
+ }
+
+ /* A numerical back reference can be fixed length if duplicate capturing
+ groups are not being used. A non-duplicate named back reference can also
+ be handled. */
+
+ if (meta_code == META_RECURSE_BYNAME ||
+ (!is_dupname && (cb->external_flags & PCRE2_DUPCAPUSED) == 0))
+ goto RECURSE_OR_BACKREF_LENGTH; /* Handle as a numbered version. */
+ }
+ goto ISNOTFIXED; /* Duplicate name or number */
+
+ /* The offset values for back references < 10 are in a separate vector
+ because otherwise they would use more than two parsed pattern elements on
+ 64-bit systems. */
+
+ case META_BACKREF:
+ if ((cb->external_options & PCRE2_MATCH_UNSET_BACKREF) != 0 ||
+ (cb->external_flags & PCRE2_DUPCAPUSED) != 0)
+ goto ISNOTFIXED;
+ group = META_DATA(*pptr);
+ if (group < 10)
+ {
+ offset = cb->small_ref_offset[group];
+ goto RECURSE_OR_BACKREF_LENGTH;
+ }
+
+ /* Fall through */
+ /* For groups >= 10 - picking up group twice does no harm. */
+
+ /* A true recursion implies not fixed length, but a subroutine call may
+ be OK. Back reference "recursions" are also failed. */
+
+ case META_RECURSE:
+ group = META_DATA(*pptr);
+ GETPLUSOFFSET(offset, pptr);
+
+ RECURSE_OR_BACKREF_LENGTH:
+ if (group > cb->bracount)
+ {
+ cb->erroroffset = offset;
+ *errcodeptr = ERR15; /* Non-existent subpattern */
+ return -1;
+ }
+ if (group == 0) goto ISNOTFIXED; /* Local recursion */
+ for (gptr = cb->parsed_pattern; *gptr != META_END; gptr++)
+ {
+ if (META_CODE(*gptr) == META_BIGVALUE) gptr++;
+ else if (*gptr == (META_CAPTURE | group)) break;
+ }
+
+ /* We must start the search for the end of the group at the first meta code
+ inside the group. Otherwise it will be treated as an enclosed group. */
+
+ gptrend = parsed_skip(gptr + 1, PSKIP_KET);
+ if (gptrend == NULL) goto PARSED_SKIP_FAILED;
+ if (pptr > gptr && pptr < gptrend) goto ISNOTFIXED; /* Local recursion */
+ for (r = recurses; r != NULL; r = r->prev) if (r->groupptr == gptr) break;
+ if (r != NULL) goto ISNOTFIXED; /* Mutual recursion */
+ this_recurse.prev = recurses;
+ this_recurse.groupptr = gptr;
+
+ /* We do not need to know the position of the end of the group, that is,
+ gptr is not used after the call to get_grouplength(). Setting the second
+ argument FALSE stops it scanning for the end when the length can be found
+ in the cache. */
+
+ gptr++;
+ grouplength = get_grouplength(&gptr, FALSE, errcodeptr, lcptr, group,
+ &this_recurse, cb);
+ if (grouplength < 0)
+ {
+ if (*errcodeptr == 0) goto ISNOTFIXED;
+ return -1; /* Error already set */
+ }
+ itemlength = grouplength;
+ break;
+
+ /* Check nested groups - advance past the initial data for each type and
+ then seek a fixed length with get_grouplength(). */
+
+ case META_COND_NAME:
+ case META_COND_NUMBER:
+ case META_COND_RNAME:
+ case META_COND_RNUMBER:
+ case META_COND_DEFINE:
+ pptr += 2 + SIZEOFFSET;
+ goto CHECK_GROUP;
+
+ case META_COND_ASSERT:
+ pptr += 1;
+ goto CHECK_GROUP;
+
+ case META_COND_VERSION:
+ pptr += 4;
+ goto CHECK_GROUP;
+
+ case META_CAPTURE:
+ group = META_DATA(*pptr);
+ /* Fall through */
+
+ case META_ATOMIC:
+ case META_NOCAPTURE:
+ pptr++;
+ CHECK_GROUP:
+ grouplength = get_grouplength(&pptr, TRUE, errcodeptr, lcptr, group,
+ recurses, cb);
+ if (grouplength < 0) return -1;
+ itemlength = grouplength;
+ break;
+
+ /* Exact repetition is OK; variable repetition is not. A repetition of zero
+ must subtract the length that has already been added. */
+
+ case META_MINMAX:
+ case META_MINMAX_PLUS:
+ case META_MINMAX_QUERY:
+ if (pptr[1] == pptr[2])
+ {
+ if (pptr[1] == 0) branchlength -= lastitemlength;
+ else itemlength = (pptr[1] - 1) * lastitemlength;
+ pptr += 2;
+ break;
+ }
+ /* Fall through */
+
+ /* Any other item means this branch does not have a fixed length. */
+
+ default:
+ ISNOTFIXED:
+ *errcodeptr = ERR25; /* Not fixed length */
+ return -1;
+ }
+
+ /* Add the item length to the branchlength, and save it for use if the next
+ thing is a quantifier. */
+
+ branchlength += itemlength;
+ lastitemlength = itemlength;
+
+ /* Ensure that the length does not overflow the limit. */
+
+ if (branchlength > LOOKBEHIND_MAX)
+ {
+ *errcodeptr = ERR87;
+ return -1;
+ }
+ }
+
+EXIT:
+*pptrptr = pptr;
+if (branchlength > cb->max_lookbehind) cb->max_lookbehind = branchlength;
+return branchlength;
+
+PARSED_SKIP_FAILED:
+*errcodeptr = ERR90;
+return -1;
+}
+
+
+
+/*************************************************
+* Set lengths in a lookbehind *
+*************************************************/
+
+/* This function is called for each lookbehind, to set the lengths in its
+branches. An error occurs if any branch does not have a fixed length that is
+less than the maximum (65535). On exit, the pointer must be left on the final
+ket.
+
+Arguments:
+ pptrptr pointer to pointer in the parsed pattern
+ errcodeptr pointer to error code
+ lcptr pointer to loop counter
+ recurses chain of recurse_check to catch mutual recursion
+ cb pointer to compile block
+
+Returns: TRUE if all is well
+ FALSE otherwise, with error code and offset set
+*/
+
+static BOOL
+set_lookbehind_lengths(uint32_t **pptrptr, int *errcodeptr, int *lcptr,
+ parsed_recurse_check *recurses, compile_block *cb)
+{
+PCRE2_SIZE offset;
+int branchlength;
+uint32_t *bptr = *pptrptr;
+
+READPLUSOFFSET(offset, bptr); /* Offset for error messages */
+*pptrptr += SIZEOFFSET;
+
+do
+ {
+ *pptrptr += 1;
+ branchlength = get_branchlength(pptrptr, errcodeptr, lcptr, recurses, cb);
+ if (branchlength < 0)
+ {
+ /* The errorcode and offset may already be set from a nested lookbehind. */
+ if (*errcodeptr == 0) *errcodeptr = ERR25;
+ if (cb->erroroffset == PCRE2_UNSET) cb->erroroffset = offset;
+ return FALSE;
+ }
+ *bptr |= branchlength; /* branchlength never more than 65535 */
+ bptr = *pptrptr;
+ }
+while (*bptr == META_ALT);
+
+return TRUE;
+}
+
+
+
+/*************************************************
+* Check parsed pattern lookbehinds *
+*************************************************/
+
+/* This function is called at the end of parsing a pattern if any lookbehinds
+were encountered. It scans the parsed pattern for them, calling
+set_lookbehind_lengths() for each one. At the start, the errorcode is zero and
+the error offset is marked unset. The enables the functions above not to
+override settings from deeper nestings.
+
+Arguments cb points to the compile block
+Returns: 0 on success, or an errorcode (cb->erroroffset will be set)
+*/
+
+static int
+check_lookbehinds(compile_block *cb)
+{
+uint32_t *pptr;
+int errorcode = 0;
+int loopcount = 0;
+
+cb->erroroffset = PCRE2_UNSET;
+
+for (pptr = cb->parsed_pattern; *pptr != META_END; pptr++)
+ {
+ if (*pptr < META_END) continue; /* Literal */
+
+ switch (META_CODE(*pptr))
+ {
+ default:
+ return ERR70; /* Unrecognized meta code */
+
+ case META_ESCAPE:
+ if (*pptr - META_ESCAPE == ESC_P || *pptr - META_ESCAPE == ESC_p)
+ pptr += 1;
+ break;
+
+ case META_ACCEPT:
+ case META_ALT:
+ case META_ASTERISK:
+ case META_ASTERISK_PLUS:
+ case META_ASTERISK_QUERY:
+ case META_ATOMIC:
+ case META_BACKREF:
+ case META_CAPTURE:
+ case META_CIRCUMFLEX:
+ case META_CLASS:
+ case META_CLASS_EMPTY:
+ case META_CLASS_EMPTY_NOT:
+ case META_CLASS_END:
+ case META_CLASS_NOT:
+ case META_COMMIT:
+ case META_COND_ASSERT:
+ case META_DOLLAR:
+ case META_DOT:
+ case META_FAIL:
+ case META_KET:
+ case META_LOOKAHEAD:
+ case META_LOOKAHEADNOT:
+ case META_NOCAPTURE:
+ case META_PLUS:
+ case META_PLUS_PLUS:
+ case META_PLUS_QUERY:
+ case META_PRUNE:
+ case META_QUERY:
+ case META_QUERY_PLUS:
+ case META_QUERY_QUERY:
+ case META_RANGE_ESCAPED:
+ case META_RANGE_LITERAL:
+ case META_SKIP:
+ case META_THEN:
+ break;
+
+ case META_RECURSE:
+ pptr += SIZEOFFSET;
+ break;
+
+ case META_BACKREF_BYNAME:
+ case META_COND_DEFINE:
+ case META_COND_NAME:
+ case META_COND_NUMBER:
+ case META_COND_RNAME:
+ case META_COND_RNUMBER:
+ case META_RECURSE_BYNAME:
+ pptr += 1 + SIZEOFFSET;
+ break;
+
+ case META_CALLOUT_STRING:
+ pptr += 3 + SIZEOFFSET;
+ break;
+
+ case META_BIGVALUE:
+ case META_OPTIONS:
+ case META_POSIX:
+ case META_POSIX_NEG:
+ pptr += 1;
+ break;
+
+ case META_MINMAX:
+ case META_MINMAX_QUERY:
+ case META_MINMAX_PLUS:
+ pptr += 2;
+ break;
+
+ case META_CALLOUT_NUMBER:
+ case META_COND_VERSION:
+ pptr += 3;
+ break;
+
+ case META_MARK:
+ case META_COMMIT_ARG:
+ case META_PRUNE_ARG:
+ case META_SKIP_ARG:
+ case META_THEN_ARG:
+ pptr += 1 + pptr[1];
+ break;
+
+ case META_LOOKBEHIND:
+ case META_LOOKBEHINDNOT:
+ if (!set_lookbehind_lengths(&pptr, &errorcode, &loopcount, NULL, cb))
+ return errorcode;
+ break;
+ }
+ }
+
+return 0;
+}
+
+
+
+/*************************************************
+* External function to compile a pattern *
+*************************************************/
+
+/* This function reads a regular expression in the form of a string and returns
+a pointer to a block of store holding a compiled version of the expression.
+
+Arguments:
+ pattern the regular expression
+ patlen the length of the pattern, or PCRE2_ZERO_TERMINATED
+ options option bits
+ errorptr pointer to errorcode
+ erroroffset pointer to error offset
+ ccontext points to a compile context or is NULL
+
+Returns: pointer to compiled data block, or NULL on error,
+ with errorcode and erroroffset set
+*/
+
+PCRE2_EXP_DEFN pcre2_code * PCRE2_CALL_CONVENTION
+pcre2_compile(PCRE2_SPTR pattern, PCRE2_SIZE patlen, uint32_t options,
+ int *errorptr, PCRE2_SIZE *erroroffset, pcre2_compile_context *ccontext)
+{
+BOOL utf; /* Set TRUE for UTF mode */
+BOOL has_lookbehind = FALSE; /* Set TRUE if a lookbehind is found */
+BOOL zero_terminated; /* Set TRUE for zero-terminated pattern */
+pcre2_real_code *re = NULL; /* What we will return */
+compile_block cb; /* "Static" compile-time data */
+const uint8_t *tables; /* Char tables base pointer */
+
+PCRE2_UCHAR *code; /* Current pointer in compiled code */
+PCRE2_SPTR codestart; /* Start of compiled code */
+PCRE2_SPTR ptr; /* Current pointer in pattern */
+uint32_t *pptr; /* Current pointer in parsed pattern */
+
+PCRE2_SIZE length = 1; /* Allow for final END opcode */
+PCRE2_SIZE usedlength; /* Actual length used */
+PCRE2_SIZE re_blocksize; /* Size of memory block */
+PCRE2_SIZE big32count = 0; /* 32-bit literals >= 0x80000000 */
+PCRE2_SIZE parsed_size_needed; /* Needed for parsed pattern */
+
+int32_t firstcuflags, reqcuflags; /* Type of first/req code unit */
+uint32_t firstcu, reqcu; /* Value of first/req code unit */
+uint32_t setflags = 0; /* NL and BSR set flags */
+
+uint32_t skipatstart; /* When checking (*UTF) etc */
+uint32_t limit_heap = UINT32_MAX;
+uint32_t limit_match = UINT32_MAX; /* Unset match limits */
+uint32_t limit_depth = UINT32_MAX;
+
+int newline = 0; /* Unset; can be set by the pattern */
+int bsr = 0; /* Unset; can be set by the pattern */
+int errorcode = 0; /* Initialize to avoid compiler warn */
+int regexrc; /* Return from compile */
+
+uint32_t i; /* Local loop counter */
+
+/* Comments at the head of this file explain about these variables. */
+
+uint32_t stack_groupinfo[GROUPINFO_DEFAULT_SIZE];
+uint32_t stack_parsed_pattern[PARSED_PATTERN_DEFAULT_SIZE];
+named_group named_groups[NAMED_GROUP_LIST_SIZE];
+
+/* The workspace is used in different ways in the different compiling phases.
+It needs to be 16-bit aligned for the preliminary parsing scan. */
+
+uint32_t c16workspace[C16_WORK_SIZE];
+PCRE2_UCHAR *cworkspace = (PCRE2_UCHAR *)c16workspace;
+
+
+/* -------------- Check arguments and set up the pattern ----------------- */
+
+/* There must be error code and offset pointers. */
+
+if (errorptr == NULL || erroroffset == NULL) return NULL;
+*errorptr = ERR0;
+*erroroffset = 0;
+
+/* There must be a pattern! */
+
+if (pattern == NULL)
+ {
+ *errorptr = ERR16;
+ return NULL;
+ }
+
+/* A NULL compile context means "use a default context" */
+
+if (ccontext == NULL)
+ ccontext = (pcre2_compile_context *)(&PRIV(default_compile_context));
+
+/* Check that all undefined public option bits are zero. */
+
+if ((options & ~PUBLIC_COMPILE_OPTIONS) != 0 ||
+ (ccontext->extra_options & ~PUBLIC_COMPILE_EXTRA_OPTIONS) != 0)
+ {
+ *errorptr = ERR17;
+ return NULL;
+ }
+
+if ((options & PCRE2_LITERAL) != 0 &&
+ ((options & ~PUBLIC_LITERAL_COMPILE_OPTIONS) != 0 ||
+ (ccontext->extra_options & ~PUBLIC_LITERAL_COMPILE_EXTRA_OPTIONS) != 0))
+ {
+ *errorptr = ERR92;
+ return NULL;
+ }
+
+/* A zero-terminated pattern is indicated by the special length value
+PCRE2_ZERO_TERMINATED. Check for an overlong pattern. */
+
+if ((zero_terminated = (patlen == PCRE2_ZERO_TERMINATED)))
+ patlen = PRIV(strlen)(pattern);
+
+if (patlen > ccontext->max_pattern_length)
+ {
+ *errorptr = ERR88;
+ return NULL;
+ }
+
+/* From here on, all returns from this function should end up going via the
+EXIT label. */
+
+
+/* ------------ Initialize the "static" compile data -------------- */
+
+tables = (ccontext->tables != NULL)? ccontext->tables : PRIV(default_tables);
+
+cb.lcc = tables + lcc_offset; /* Individual */
+cb.fcc = tables + fcc_offset; /* character */
+cb.cbits = tables + cbits_offset; /* tables */
+cb.ctypes = tables + ctypes_offset;
+
+cb.assert_depth = 0;
+cb.bracount = 0;
+cb.cx = ccontext;
+cb.dupnames = FALSE;
+cb.end_pattern = pattern + patlen;
+cb.erroroffset = 0;
+cb.external_flags = 0;
+cb.external_options = options;
+cb.groupinfo = stack_groupinfo;
+cb.had_recurse = FALSE;
+cb.lastcapture = 0;
+cb.max_lookbehind = 0;
+cb.name_entry_size = 0;
+cb.name_table = NULL;
+cb.named_groups = named_groups;
+cb.named_group_list_size = NAMED_GROUP_LIST_SIZE;
+cb.names_found = 0;
+cb.open_caps = NULL;
+cb.parens_depth = 0;
+cb.parsed_pattern = stack_parsed_pattern;
+cb.req_varyopt = 0;
+cb.start_code = cworkspace;
+cb.start_pattern = pattern;
+cb.start_workspace = cworkspace;
+cb.workspace_size = COMPILE_WORK_SIZE;
+
+/* Maximum back reference and backref bitmap. The bitmap records up to 31 back
+references to help in deciding whether (.*) can be treated as anchored or not.
+*/
+
+cb.top_backref = 0;
+cb.backref_map = 0;
+
+/* Escape sequences \1 to \9 are always back references, but as they are only
+two characters long, only two elements can be used in the parsed_pattern
+vector. The first contains the reference, and we'd like to use the second to
+record the offset in the pattern, so that forward references to non-existent
+groups can be diagnosed later with an offset. However, on 64-bit systems,
+PCRE2_SIZE won't fit. Instead, we have a vector of offsets for the first
+occurrence of \1 to \9, indexed by the second parsed_pattern value. All other
+references have enough space for the offset to be put into the parsed pattern.
+*/
+
+for (i = 0; i < 10; i++) cb.small_ref_offset[i] = PCRE2_UNSET;
+
+
+/* --------------- Start looking at the pattern --------------- */
+
+/* Unless PCRE2_LITERAL is set, check for global one-time option settings at
+the start of the pattern, and remember the offset to the actual regex. With
+valgrind support, make the terminator of a zero-terminated pattern
+inaccessible. This catches bugs that would otherwise only show up for
+non-zero-terminated patterns. */
+
+#ifdef SUPPORT_VALGRIND
+if (zero_terminated) VALGRIND_MAKE_MEM_NOACCESS(pattern + patlen, CU2BYTES(1));
+#endif
+
+ptr = pattern;
+skipatstart = 0;
+
+if ((options & PCRE2_LITERAL) == 0)
+ {
+ while (patlen - skipatstart >= 2 &&
+ ptr[skipatstart] == CHAR_LEFT_PARENTHESIS &&
+ ptr[skipatstart+1] == CHAR_ASTERISK)
+ {
+ for (i = 0; i < sizeof(pso_list)/sizeof(pso); i++)
+ {
+ uint32_t c, pp;
+ pso *p = pso_list + i;
+
+ if (patlen - skipatstart - 2 >= p->length &&
+ PRIV(strncmp_c8)(ptr + skipatstart + 2, (char *)(p->name),
+ p->length) == 0)
+ {
+ skipatstart += p->length + 2;
+ switch(p->type)
+ {
+ case PSO_OPT:
+ cb.external_options |= p->value;
+ break;
+
+ case PSO_FLG:
+ setflags |= p->value;
+ break;
+
+ case PSO_NL:
+ newline = p->value;
+ setflags |= PCRE2_NL_SET;
+ break;
+
+ case PSO_BSR:
+ bsr = p->value;
+ setflags |= PCRE2_BSR_SET;
+ break;
+
+ case PSO_LIMM:
+ case PSO_LIMD:
+ case PSO_LIMH:
+ c = 0;
+ pp = skipatstart;
+ if (!IS_DIGIT(ptr[pp]))
+ {
+ errorcode = ERR60;
+ ptr += pp;
+ goto HAD_EARLY_ERROR;
+ }
+ while (IS_DIGIT(ptr[pp]))
+ {
+ if (c > UINT32_MAX / 10 - 1) break; /* Integer overflow */
+ c = c*10 + (ptr[pp++] - CHAR_0);
+ }
+ if (ptr[pp++] != CHAR_RIGHT_PARENTHESIS)
+ {
+ errorcode = ERR60;
+ ptr += pp;
+ goto HAD_EARLY_ERROR;
+ }
+ if (p->type == PSO_LIMH) limit_heap = c;
+ else if (p->type == PSO_LIMM) limit_match = c;
+ else limit_depth = c;
+ skipatstart += pp - skipatstart;
+ break;
+ }
+ break; /* Out of the table scan loop */
+ }
+ }
+ if (i >= sizeof(pso_list)/sizeof(pso)) break; /* Out of pso loop */
+ }
+ }
+
+/* End of pattern-start options; advance to start of real regex. */
+
+ptr += skipatstart;
+
+/* Can't support UTF or UCP unless PCRE2 has been compiled with UTF support. */
+
+#ifndef SUPPORT_UNICODE
+if ((cb.external_options & (PCRE2_UTF|PCRE2_UCP)) != 0)
+ {
+ errorcode = ERR32;
+ goto HAD_EARLY_ERROR;
+ }
+#endif
+
+/* Check UTF. We have the original options in 'options', with that value as
+modified by (*UTF) etc in cb->external_options. The extra option
+PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not permitted in UTF-16 mode because the
+surrogate code points cannot be represented in UTF-16. */
+
+utf = (cb.external_options & PCRE2_UTF) != 0;
+if (utf)
+ {
+ if ((options & PCRE2_NEVER_UTF) != 0)
+ {
+ errorcode = ERR74;
+ goto HAD_EARLY_ERROR;
+ }
+ if ((options & PCRE2_NO_UTF_CHECK) == 0 &&
+ (errorcode = PRIV(valid_utf)(pattern, patlen, erroroffset)) != 0)
+ goto HAD_ERROR; /* Offset was set by valid_utf() */
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+ if ((ccontext->extra_options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0)
+ {
+ errorcode = ERR91;
+ goto HAD_EARLY_ERROR;
+ }
+#endif
+ }
+
+/* Check UCP lockout. */
+
+if ((cb.external_options & (PCRE2_UCP|PCRE2_NEVER_UCP)) ==
+ (PCRE2_UCP|PCRE2_NEVER_UCP))
+ {
+ errorcode = ERR75;
+ goto HAD_EARLY_ERROR;
+ }
+
+/* Process the BSR setting. */
+
+if (bsr == 0) bsr = ccontext->bsr_convention;
+
+/* Process the newline setting. */
+
+if (newline == 0) newline = ccontext->newline_convention;
+cb.nltype = NLTYPE_FIXED;
+switch(newline)
+ {
+ case PCRE2_NEWLINE_CR:
+ cb.nllen = 1;
+ cb.nl[0] = CHAR_CR;
+ break;
+
+ case PCRE2_NEWLINE_LF:
+ cb.nllen = 1;
+ cb.nl[0] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_NUL:
+ cb.nllen = 1;
+ cb.nl[0] = CHAR_NUL;
+ break;
+
+ case PCRE2_NEWLINE_CRLF:
+ cb.nllen = 2;
+ cb.nl[0] = CHAR_CR;
+ cb.nl[1] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_ANY:
+ cb.nltype = NLTYPE_ANY;
+ break;
+
+ case PCRE2_NEWLINE_ANYCRLF:
+ cb.nltype = NLTYPE_ANYCRLF;
+ break;
+
+ default:
+ errorcode = ERR56;
+ goto HAD_EARLY_ERROR;
+ }
+
+/* Pre-scan the pattern to do two things: (1) Discover the named groups and
+their numerical equivalents, so that this information is always available for
+the remaining processing. (2) At the same time, parse the pattern and put a
+processed version into the parsed_pattern vector. This has escapes interpreted
+and comments removed (amongst other things).
+
+In all but one case, when PCRE2_AUTO_CALLOUT is not set, the number of unsigned
+32-bit ints in the parsed pattern is bounded by the length of the pattern plus
+one (for the terminator) plus four if PCRE2_EXTRA_WORD or PCRE2_EXTRA_LINE is
+set. The exceptional case is when running in 32-bit, non-UTF mode, when literal
+characters greater than META_END (0x80000000) have to be coded as two units. In
+this case, therefore, we scan the pattern to check for such values. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (!utf)
+ {
+ PCRE2_SPTR p;
+ for (p = ptr; p < cb.end_pattern; p++) if (*p >= META_END) big32count++;
+ }
+#endif
+
+/* Ensure that the parsed pattern buffer is big enough. When PCRE2_AUTO_CALLOUT
+is set we have to assume a numerical callout (4 elements) for each character
+plus one at the end. This is overkill, but memory is plentiful these days. For
+many smaller patterns the vector on the stack (which was set up above) can be
+used. */
+
+parsed_size_needed = patlen - skipatstart + big32count;
+
+if ((ccontext->extra_options &
+ (PCRE2_EXTRA_MATCH_WORD|PCRE2_EXTRA_MATCH_LINE)) != 0)
+ parsed_size_needed += 4;
+
+if ((options & PCRE2_AUTO_CALLOUT) != 0)
+ parsed_size_needed = (parsed_size_needed + 1) * 5;
+
+if (parsed_size_needed >= PARSED_PATTERN_DEFAULT_SIZE)
+ {
+ uint32_t *heap_parsed_pattern = ccontext->memctl.malloc(
+ (parsed_size_needed + 1) * sizeof(uint32_t), ccontext->memctl.memory_data);
+ if (heap_parsed_pattern == NULL)
+ {
+ *errorptr = ERR21;
+ goto EXIT;
+ }
+ cb.parsed_pattern = heap_parsed_pattern;
+ }
+cb.parsed_pattern_end = cb.parsed_pattern + parsed_size_needed + 1;
+
+/* Do the parsing scan. */
+
+errorcode = parse_regex(ptr, cb.external_options, &has_lookbehind, &cb);
+if (errorcode != 0) goto HAD_CB_ERROR;
+
+/* Workspace is needed to remember information about numbered groups: whether a
+group can match an empty string and what its fixed length is. This is done to
+avoid the possibility of recursive references causing very long compile times
+when checking these features. Unnumbered groups do not have this exposure since
+they cannot be referenced. We use an indexed vector for this purpose. If there
+are sufficiently few groups, the default vector on the stack, as set up above,
+can be used. Otherwise we have to get/free a special vector. The vector must be
+initialized to zero. */
+
+if (cb.bracount >= GROUPINFO_DEFAULT_SIZE)
+ {
+ cb.groupinfo = ccontext->memctl.malloc(
+ (cb.bracount + 1)*sizeof(uint32_t), ccontext->memctl.memory_data);
+ if (cb.groupinfo == NULL)
+ {
+ errorcode = ERR21;
+ cb.erroroffset = 0;
+ goto HAD_CB_ERROR;
+ }
+ }
+memset(cb.groupinfo, 0, (cb.bracount + 1) * sizeof(uint32_t));
+
+/* If there were any lookbehinds, scan the parsed pattern to figure out their
+lengths. */
+
+if (has_lookbehind)
+ {
+ errorcode = check_lookbehinds(&cb);
+ if (errorcode != 0) goto HAD_CB_ERROR;
+ }
+
+/* For debugging, there is a function that shows the parsed data vector. */
+
+#ifdef DEBUG_SHOW_PARSED
+fprintf(stderr, "+++ Pre-scan complete:\n");
+show_parsed(&cb);
+#endif
+
+/* For debugging capturing information this code can be enabled. */
+
+#ifdef DEBUG_SHOW_CAPTURES
+ {
+ named_group *ng = cb.named_groups;
+ fprintf(stderr, "+++Captures: %d\n", cb.bracount);
+ for (i = 0; i < cb.names_found; i++, ng++)
+ {
+ fprintf(stderr, "+++%3d %.*s\n", ng->number, ng->length, ng->name);
+ }
+ }
+#endif
+
+/* Pretend to compile the pattern while actually just accumulating the amount
+of memory required in the 'length' variable. This behaviour is triggered by
+passing a non-NULL final argument to compile_regex(). We pass a block of
+workspace (cworkspace) for it to compile parts of the pattern into; the
+compiled code is discarded when it is no longer needed, so hopefully this
+workspace will never overflow, though there is a test for its doing so.
+
+On error, errorcode will be set non-zero, so we don't need to look at the
+result of the function. The initial options have been put into the cb block,
+but we still have to pass a separate options variable (the first argument)
+because the options may change as the pattern is processed. */
+
+cb.erroroffset = patlen; /* For any subsequent errors that do not set it */
+pptr = cb.parsed_pattern;
+code = cworkspace;
+*code = OP_BRA;
+
+(void)compile_regex(cb.external_options, &code, &pptr, &errorcode, 0, &firstcu,
+ &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, &length);
+
+if (errorcode != 0) goto HAD_CB_ERROR; /* Offset is in cb.erroroffset */
+
+/* This should be caught in compile_regex(), but just in case... */
+
+if (length > MAX_PATTERN_SIZE)
+ {
+ errorcode = ERR20;
+ goto HAD_CB_ERROR;
+ }
+
+/* Compute the size of, and then get and initialize, the data block for storing
+the compiled pattern and names table. Integer overflow should no longer be
+possible because nowadays we limit the maximum value of cb.names_found and
+cb.name_entry_size. */
+
+re_blocksize = sizeof(pcre2_real_code) +
+ CU2BYTES(length +
+ (PCRE2_SIZE)cb.names_found * (PCRE2_SIZE)cb.name_entry_size);
+re = (pcre2_real_code *)
+ ccontext->memctl.malloc(re_blocksize, ccontext->memctl.memory_data);
+if (re == NULL)
+ {
+ errorcode = ERR21;
+ goto HAD_CB_ERROR;
+ }
+
+/* The compiler may put padding at the end of the pcre2_real_code structure in
+order to round it up to a multiple of 4 or 8 bytes. This means that when a
+compiled pattern is copied (for example, when serialized) undefined bytes are
+read, and this annoys debuggers such as valgrind. To avoid this, we explicitly
+write to the last 8 bytes of the structure before setting the fields. */
+
+memset((char *)re + sizeof(pcre2_real_code) - 8, 0, 8);
+re->memctl = ccontext->memctl;
+re->tables = tables;
+re->executable_jit = NULL;
+memset(re->start_bitmap, 0, 32 * sizeof(uint8_t));
+re->blocksize = re_blocksize;
+re->magic_number = MAGIC_NUMBER;
+re->compile_options = options;
+re->overall_options = cb.external_options;
+re->extra_options = ccontext->extra_options;
+re->flags = PCRE2_CODE_UNIT_WIDTH/8 | cb.external_flags | setflags;
+re->limit_heap = limit_heap;
+re->limit_match = limit_match;
+re->limit_depth = limit_depth;
+re->first_codeunit = 0;
+re->last_codeunit = 0;
+re->bsr_convention = bsr;
+re->newline_convention = newline;
+re->max_lookbehind = 0;
+re->minlength = 0;
+re->top_bracket = 0;
+re->top_backref = 0;
+re->name_entry_size = cb.name_entry_size;
+re->name_count = cb.names_found;
+
+/* The basic block is immediately followed by the name table, and the compiled
+code follows after that. */
+
+codestart = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ re->name_entry_size * re->name_count;
+
+/* Update the compile data block for the actual compile. The starting points of
+the name/number translation table and of the code are passed around in the
+compile data block. The start/end pattern and initial options are already set
+from the pre-compile phase, as is the name_entry_size field. */
+
+cb.parens_depth = 0;
+cb.assert_depth = 0;
+cb.lastcapture = 0;
+cb.name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
+cb.start_code = codestart;
+cb.req_varyopt = 0;
+cb.had_accept = FALSE;
+cb.had_pruneorskip = FALSE;
+cb.open_caps = NULL;
+
+/* If any named groups were found, create the name/number table from the list
+created in the pre-pass. */
+
+if (cb.names_found > 0)
+ {
+ named_group *ng = cb.named_groups;
+ for (i = 0; i < cb.names_found; i++, ng++)
+ add_name_to_table(&cb, ng->name, ng->length, ng->number, i);
+ }
+
+/* Set up a starting, non-extracting bracket, then compile the expression. On
+error, errorcode will be set non-zero, so we don't need to look at the result
+of the function here. */
+
+pptr = cb.parsed_pattern;
+code = (PCRE2_UCHAR *)codestart;
+*code = OP_BRA;
+regexrc = compile_regex(re->overall_options, &code, &pptr, &errorcode, 0,
+ &firstcu, &firstcuflags, &reqcu, &reqcuflags, NULL, &cb, NULL);
+if (regexrc < 0) re->flags |= PCRE2_MATCH_EMPTY;
+re->top_bracket = cb.bracount;
+re->top_backref = cb.top_backref;
+re->max_lookbehind = cb.max_lookbehind;
+
+if (cb.had_accept)
+ {
+ reqcu = 0; /* Must disable after (*ACCEPT) */
+ reqcuflags = REQ_NONE;
+ }
+
+/* Fill in the final opcode and check for disastrous overflow. If no overflow,
+but the estimated length exceeds the really used length, adjust the value of
+re->blocksize, and if valgrind support is configured, mark the extra allocated
+memory as unaddressable, so that any out-of-bound reads can be detected. */
+
+*code++ = OP_END;
+usedlength = code - codestart;
+if (usedlength > length) errorcode = ERR23; else
+ {
+ re->blocksize -= CU2BYTES(length - usedlength);
+#ifdef SUPPORT_VALGRIND
+ VALGRIND_MAKE_MEM_NOACCESS(code, CU2BYTES(length - usedlength));
+#endif
+ }
+
+/* Scan the pattern for recursion/subroutine calls and convert the group
+numbers into offsets. Maintain a small cache so that repeated groups containing
+recursions are efficiently handled. */
+
+#define RSCAN_CACHE_SIZE 8
+
+if (errorcode == 0 && cb.had_recurse)
+ {
+ PCRE2_UCHAR *rcode;
+ PCRE2_SPTR rgroup;
+ unsigned int ccount = 0;
+ int start = RSCAN_CACHE_SIZE;
+ recurse_cache rc[RSCAN_CACHE_SIZE];
+
+ for (rcode = (PCRE2_UCHAR *)find_recurse(codestart, utf);
+ rcode != NULL;
+ rcode = (PCRE2_UCHAR *)find_recurse(rcode + 1 + LINK_SIZE, utf))
+ {
+ int p, groupnumber;
+
+ groupnumber = (int)GET(rcode, 1);
+ if (groupnumber == 0) rgroup = codestart; else
+ {
+ PCRE2_SPTR search_from = codestart;
+ rgroup = NULL;
+ for (i = 0, p = start; i < ccount; i++, p = (p + 1) & 7)
+ {
+ if (groupnumber == rc[p].groupnumber)
+ {
+ rgroup = rc[p].group;
+ break;
+ }
+
+ /* Group n+1 must always start to the right of group n, so we can save
+ search time below when the new group number is greater than any of the
+ previously found groups. */
+
+ if (groupnumber > rc[p].groupnumber) search_from = rc[p].group;
+ }
+
+ if (rgroup == NULL)
+ {
+ rgroup = PRIV(find_bracket)(search_from, utf, groupnumber);
+ if (rgroup == NULL)
+ {
+ errorcode = ERR53;
+ break;
+ }
+ if (--start < 0) start = RSCAN_CACHE_SIZE - 1;
+ rc[start].groupnumber = groupnumber;
+ rc[start].group = rgroup;
+ if (ccount < RSCAN_CACHE_SIZE) ccount++;
+ }
+ }
+
+ PUT(rcode, 1, rgroup - codestart);
+ }
+ }
+
+/* In rare debugging situations we sometimes need to look at the compiled code
+at this stage. */
+
+#ifdef DEBUG_CALL_PRINTINT
+pcre2_printint(re, stderr, TRUE);
+fprintf(stderr, "Length=%lu Used=%lu\n", length, usedlength);
+#endif
+
+/* Unless disabled, check whether any single character iterators can be
+auto-possessified. The function overwrites the appropriate opcode values, so
+the type of the pointer must be cast. NOTE: the intermediate variable "temp" is
+used in this code because at least one compiler gives a warning about loss of
+"const" attribute if the cast (PCRE2_UCHAR *)codestart is used directly in the
+function call. */
+
+if (errorcode == 0 && (re->overall_options & PCRE2_NO_AUTO_POSSESS) == 0)
+ {
+ PCRE2_UCHAR *temp = (PCRE2_UCHAR *)codestart;
+ if (PRIV(auto_possessify)(temp, utf, &cb) != 0) errorcode = ERR80;
+ }
+
+/* Failed to compile, or error while post-processing. */
+
+if (errorcode != 0) goto HAD_CB_ERROR;
+
+/* Successful compile. If the anchored option was not passed, set it if
+we can determine that the pattern is anchored by virtue of ^ characters or \A
+or anything else, such as starting with non-atomic .* when DOTALL is set and
+there are no occurrences of *PRUNE or *SKIP (though there is an option to
+disable this case). */
+
+if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
+ is_anchored(codestart, 0, &cb, 0, FALSE))
+ re->overall_options |= PCRE2_ANCHORED;
+
+/* Set up the first code unit or startline flag, the required code unit, and
+then study the pattern. This code need not be obeyed if PCRE2_NO_START_OPTIMIZE
+is set, as the data it would create will not be used. Note that a first code
+unit (but not the startline flag) is useful for anchored patterns because it
+can still give a quick "no match" and also avoid searching for a last code
+unit. */
+
+if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+ {
+ /* If we do not have a first code unit, see if there is one that is asserted
+ (these are not saved during the compile because they can cause conflicts with
+ actual literals that follow). */
+
+ if (firstcuflags < 0)
+ firstcu = find_firstassertedcu(codestart, &firstcuflags, 0);
+
+ /* Save the data for a first code unit. */
+
+ if (firstcuflags >= 0)
+ {
+ re->first_codeunit = firstcu;
+ re->flags |= PCRE2_FIRSTSET;
+
+ /* Handle caseless first code units. */
+
+ if ((firstcuflags & REQ_CASELESS) != 0)
+ {
+ if (firstcu < 128 || (!utf && firstcu < 255))
+ {
+ if (cb.fcc[firstcu] != firstcu) re->flags |= PCRE2_FIRSTCASELESS;
+ }
+
+ /* The first code unit is > 128 in UTF mode, or > 255 otherwise. In
+ 8-bit UTF mode, codepoints in the range 128-255 are introductory code
+ points and cannot have another case. In 16-bit and 32-bit modes, we can
+ check wide characters when UTF (and therefore UCP) is supported. */
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ else if (firstcu <= MAX_UTF_CODE_POINT &&
+ UCD_OTHERCASE(firstcu) != firstcu)
+ re->flags |= PCRE2_FIRSTCASELESS;
+#endif
+ }
+ }
+
+ /* When there is no first code unit, for non-anchored patterns, see if we can
+ set the PCRE2_STARTLINE flag. This is helpful for multiline matches when all
+ branches start with ^ and also when all branches start with non-atomic .* for
+ non-DOTALL matches when *PRUNE and SKIP are not present. (There is an option
+ that disables this case.) */
+
+ else if ((re->overall_options & PCRE2_ANCHORED) == 0 &&
+ is_startline(codestart, 0, &cb, 0, FALSE))
+ re->flags |= PCRE2_STARTLINE;
+
+ /* Handle the "required code unit", if one is set. In the case of an anchored
+ pattern, do this only if it follows a variable length item in the pattern. */
+
+ if (reqcuflags >= 0 &&
+ ((re->overall_options & PCRE2_ANCHORED) == 0 ||
+ (reqcuflags & REQ_VARY) != 0))
+ {
+ re->last_codeunit = reqcu;
+ re->flags |= PCRE2_LASTSET;
+
+ /* Handle caseless required code units as for first code units (above). */
+
+ if ((reqcuflags & REQ_CASELESS) != 0)
+ {
+ if (reqcu < 128 || (!utf && reqcu < 255))
+ {
+ if (cb.fcc[reqcu] != reqcu) re->flags |= PCRE2_LASTCASELESS;
+ }
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ else if (reqcu <= MAX_UTF_CODE_POINT && UCD_OTHERCASE(reqcu) != reqcu)
+ re->flags |= PCRE2_LASTCASELESS;
+#endif
+ }
+ }
+
+ /* Finally, study the compiled pattern to set up information such as a bitmap
+ of starting code units and a minimum matching length. */
+
+ if (PRIV(study)(re) != 0)
+ {
+ errorcode = ERR31;
+ goto HAD_CB_ERROR;
+ }
+ } /* End of start-of-match optimizations. */
+
+/* Control ends up here in all cases. When running under valgrind, make a
+pattern's terminating zero defined again. If memory was obtained for the parsed
+version of the pattern, free it before returning. Also free the list of named
+groups if a larger one had to be obtained, and likewise the group information
+vector. */
+
+EXIT:
+#ifdef SUPPORT_VALGRIND
+if (zero_terminated) VALGRIND_MAKE_MEM_DEFINED(pattern + patlen, CU2BYTES(1));
+#endif
+if (cb.parsed_pattern != stack_parsed_pattern)
+ ccontext->memctl.free(cb.parsed_pattern, ccontext->memctl.memory_data);
+if (cb.named_group_list_size > NAMED_GROUP_LIST_SIZE)
+ ccontext->memctl.free((void *)cb.named_groups, ccontext->memctl.memory_data);
+if (cb.groupinfo != stack_groupinfo)
+ ccontext->memctl.free((void *)cb.groupinfo, ccontext->memctl.memory_data);
+return re; /* Will be NULL after an error */
+
+/* Errors discovered in parse_regex() set the offset value in the compile
+block. Errors discovered before it is called must compute it from the ptr
+value. After parse_regex() is called, the offset in the compile block is set to
+the end of the pattern, but certain errors in compile_regex() may reset it if
+an offset is available in the parsed pattern. */
+
+HAD_CB_ERROR:
+ptr = pattern + cb.erroroffset;
+
+HAD_EARLY_ERROR:
+*erroroffset = ptr - pattern;
+
+HAD_ERROR:
+*errorptr = errorcode;
+pcre2_code_free(re);
+re = NULL;
+goto EXIT;
+}
+
+/* End of pcre2_compile.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_config.c b/test/monniaux/pcre2-10.32/pcre2_config.c
new file mode 100644
index 00000000..e487b102
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_config.c
@@ -0,0 +1,246 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2017 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* Save the configured link size, which is in bytes. In 16-bit and 32-bit modes
+its value gets changed by pcre2_internal.h to be in code units. */
+
+static int configured_link_size = LINK_SIZE;
+
+#include "pcre2_internal.h"
+
+/* These macros are the standard way of turning unquoted text into C strings.
+They allow macros like PCRE2_MAJOR to be defined without quotes, which is
+convenient for user programs that want to test their values. */
+
+#define STRING(a) # a
+#define XSTRING(s) STRING(s)
+
+
+/*************************************************
+* Return info about what features are configured *
+*************************************************/
+
+/* If where is NULL, the length of memory required is returned.
+
+Arguments:
+ what what information is required
+ where where to put the information
+
+Returns: 0 if a numerical value is returned
+ >= 0 if a string value
+ PCRE2_ERROR_BADOPTION if "where" not recognized
+ or JIT target requested when JIT not enabled
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_config(uint32_t what, void *where)
+{
+if (where == NULL) /* Requests a length */
+ {
+ switch(what)
+ {
+ default:
+ return PCRE2_ERROR_BADOPTION;
+
+ case PCRE2_CONFIG_BSR:
+ case PCRE2_CONFIG_COMPILED_WIDTHS:
+ case PCRE2_CONFIG_DEPTHLIMIT:
+ case PCRE2_CONFIG_HEAPLIMIT:
+ case PCRE2_CONFIG_JIT:
+ case PCRE2_CONFIG_LINKSIZE:
+ case PCRE2_CONFIG_MATCHLIMIT:
+ case PCRE2_CONFIG_NEVER_BACKSLASH_C:
+ case PCRE2_CONFIG_NEWLINE:
+ case PCRE2_CONFIG_PARENSLIMIT:
+ case PCRE2_CONFIG_STACKRECURSE: /* Obsolete */
+ case PCRE2_CONFIG_UNICODE:
+ return sizeof(uint32_t);
+
+ /* These are handled below */
+
+ case PCRE2_CONFIG_JITTARGET:
+ case PCRE2_CONFIG_UNICODE_VERSION:
+ case PCRE2_CONFIG_VERSION:
+ break;
+ }
+ }
+
+switch (what)
+ {
+ default:
+ return PCRE2_ERROR_BADOPTION;
+
+ case PCRE2_CONFIG_BSR:
+#ifdef BSR_ANYCRLF
+ *((uint32_t *)where) = PCRE2_BSR_ANYCRLF;
+#else
+ *((uint32_t *)where) = PCRE2_BSR_UNICODE;
+#endif
+ break;
+
+ case PCRE2_CONFIG_COMPILED_WIDTHS:
+ *((uint32_t *)where) = 0
+#ifdef SUPPORT_PCRE2_8
+ + 1
+#endif
+#ifdef SUPPORT_PCRE2_16
+ + 2
+#endif
+#ifdef SUPPORT_PCRE2_32
+ + 4
+#endif
+ ;
+ break;
+
+ case PCRE2_CONFIG_DEPTHLIMIT:
+ *((uint32_t *)where) = MATCH_LIMIT_DEPTH;
+ break;
+
+ case PCRE2_CONFIG_HEAPLIMIT:
+ *((uint32_t *)where) = HEAP_LIMIT;
+ break;
+
+ case PCRE2_CONFIG_JIT:
+#ifdef SUPPORT_JIT
+ *((uint32_t *)where) = 1;
+#else
+ *((uint32_t *)where) = 0;
+#endif
+ break;
+
+ case PCRE2_CONFIG_JITTARGET:
+#ifdef SUPPORT_JIT
+ {
+ const char *v = PRIV(jit_get_target)();
+ return (int)(1 + ((where == NULL)?
+ strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+ }
+#else
+ return PCRE2_ERROR_BADOPTION;
+#endif
+
+ case PCRE2_CONFIG_LINKSIZE:
+ *((uint32_t *)where) = (uint32_t)configured_link_size;
+ break;
+
+ case PCRE2_CONFIG_MATCHLIMIT:
+ *((uint32_t *)where) = MATCH_LIMIT;
+ break;
+
+ case PCRE2_CONFIG_NEWLINE:
+ *((uint32_t *)where) = NEWLINE_DEFAULT;
+ break;
+
+ case PCRE2_CONFIG_NEVER_BACKSLASH_C:
+#ifdef NEVER_BACKSLASH_C
+ *((uint32_t *)where) = 1;
+#else
+ *((uint32_t *)where) = 0;
+#endif
+ break;
+
+ case PCRE2_CONFIG_PARENSLIMIT:
+ *((uint32_t *)where) = PARENS_NEST_LIMIT;
+ break;
+
+ /* This is now obsolete. The stack is no longer used via recursion for
+ handling backtracking in pcre2_match(). */
+
+ case PCRE2_CONFIG_STACKRECURSE:
+ *((uint32_t *)where) = 0;
+ break;
+
+ case PCRE2_CONFIG_UNICODE_VERSION:
+ {
+#if defined SUPPORT_UNICODE
+ const char *v = PRIV(unicode_version);
+#else
+ const char *v = "Unicode not supported";
+#endif
+ return (int)(1 + ((where == NULL)?
+ strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+ }
+ break;
+
+ case PCRE2_CONFIG_UNICODE:
+#if defined SUPPORT_UNICODE
+ *((uint32_t *)where) = 1;
+#else
+ *((uint32_t *)where) = 0;
+#endif
+ break;
+
+ /* The hackery in setting "v" below is to cope with the case when
+ PCRE2_PRERELEASE is set to an empty string (which it is for real releases).
+ If the second alternative is used in this case, it does not leave a space
+ before the date. On the other hand, if all four macros are put into a single
+ XSTRING when PCRE2_PRERELEASE is not empty, an unwanted space is inserted.
+ There are problems using an "obvious" approach like this:
+
+ XSTRING(PCRE2_MAJOR) "." XSTRING(PCRE_MINOR)
+ XSTRING(PCRE2_PRERELEASE) " " XSTRING(PCRE_DATE)
+
+ because, when PCRE2_PRERELEASE is empty, this leads to an attempted expansion
+ of STRING(). The C standard states: "If (before argument substitution) any
+ argument consists of no preprocessing tokens, the behavior is undefined." It
+ turns out the gcc treats this case as a single empty string - which is what
+ we really want - but Visual C grumbles about the lack of an argument for the
+ macro. Unfortunately, both are within their rights. As there seems to be no
+ way to test for a macro's value being empty at compile time, we have to
+ resort to a runtime test. */
+
+ case PCRE2_CONFIG_VERSION:
+ {
+ const char *v = (XSTRING(Z PCRE2_PRERELEASE)[1] == 0)?
+ XSTRING(PCRE2_MAJOR.PCRE2_MINOR PCRE2_DATE) :
+ XSTRING(PCRE2_MAJOR.PCRE2_MINOR) XSTRING(PCRE2_PRERELEASE PCRE2_DATE);
+ return (int)(1 + ((where == NULL)?
+ strlen(v) : PRIV(strcpy_c8)((PCRE2_UCHAR *)where, v)));
+ }
+ }
+
+return 0;
+}
+
+/* End of pcre2_config.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_context.c b/test/monniaux/pcre2-10.32/pcre2_context.c
new file mode 100644
index 00000000..2c14df00
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_context.c
@@ -0,0 +1,476 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2017 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Default malloc/free functions *
+*************************************************/
+
+/* Ignore the "user data" argument in each case. */
+
+static void *default_malloc(size_t size, void *data)
+{
+(void)data;
+return malloc(size);
+}
+
+
+static void default_free(void *block, void *data)
+{
+(void)data;
+free(block);
+}
+
+
+
+/*************************************************
+* Get a block and save memory control *
+*************************************************/
+
+/* This internal function is called to get a block of memory in which the
+memory control data is to be stored at the start for future use.
+
+Arguments:
+ size amount of memory required
+ memctl pointer to a memctl block or NULL
+
+Returns: pointer to memory or NULL on failure
+*/
+
+extern void *
+PRIV(memctl_malloc)(size_t size, pcre2_memctl *memctl)
+{
+pcre2_memctl *newmemctl;
+void *yield = (memctl == NULL)? malloc(size) :
+ memctl->malloc(size, memctl->memory_data);
+if (yield == NULL) return NULL;
+newmemctl = (pcre2_memctl *)yield;
+if (memctl == NULL)
+ {
+ newmemctl->malloc = default_malloc;
+ newmemctl->free = default_free;
+ newmemctl->memory_data = NULL;
+ }
+else *newmemctl = *memctl;
+return yield;
+}
+
+
+
+/*************************************************
+* Create and initialize contexts *
+*************************************************/
+
+/* Initializing for compile and match contexts is done in separate, private
+functions so that these can be called from functions such as pcre2_compile()
+when an external context is not supplied. The initializing functions have an
+option to set up default memory management. */
+
+PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
+pcre2_general_context_create(void *(*private_malloc)(size_t, void *),
+ void (*private_free)(void *, void *), void *memory_data)
+{
+pcre2_general_context *gcontext;
+if (private_malloc == NULL) private_malloc = default_malloc;
+if (private_free == NULL) private_free = default_free;
+gcontext = private_malloc(sizeof(pcre2_real_general_context), memory_data);
+if (gcontext == NULL) return NULL;
+gcontext->memctl.malloc = private_malloc;
+gcontext->memctl.free = private_free;
+gcontext->memctl.memory_data = memory_data;
+return gcontext;
+}
+
+
+/* A default compile context is set up to save having to initialize at run time
+when no context is supplied to the compile function. */
+
+const pcre2_compile_context PRIV(default_compile_context) = {
+ { default_malloc, default_free, NULL }, /* Default memory handling */
+ NULL, /* Stack guard */
+ NULL, /* Stack guard data */
+ PRIV(default_tables), /* Character tables */
+ PCRE2_UNSET, /* Max pattern length */
+ BSR_DEFAULT, /* Backslash R default */
+ NEWLINE_DEFAULT, /* Newline convention */
+ PARENS_NEST_LIMIT, /* As it says */
+ 0 }; /* Extra options */
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
+pcre2_compile_context_create(pcre2_general_context *gcontext)
+{
+pcre2_compile_context *ccontext = PRIV(memctl_malloc)(
+ sizeof(pcre2_real_compile_context), (pcre2_memctl *)gcontext);
+if (ccontext == NULL) return NULL;
+*ccontext = PRIV(default_compile_context);
+if (gcontext != NULL)
+ *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext);
+return ccontext;
+}
+
+
+/* A default match context is set up to save having to initialize at run time
+when no context is supplied to a match function. */
+
+const pcre2_match_context PRIV(default_match_context) = {
+ { default_malloc, default_free, NULL },
+#ifdef SUPPORT_JIT
+ NULL,
+ NULL,
+#endif
+ NULL,
+ NULL,
+ PCRE2_UNSET, /* Offset limit */
+ HEAP_LIMIT,
+ MATCH_LIMIT,
+ MATCH_LIMIT_DEPTH };
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
+pcre2_match_context_create(pcre2_general_context *gcontext)
+{
+pcre2_match_context *mcontext = PRIV(memctl_malloc)(
+ sizeof(pcre2_real_match_context), (pcre2_memctl *)gcontext);
+if (mcontext == NULL) return NULL;
+*mcontext = PRIV(default_match_context);
+if (gcontext != NULL)
+ *((pcre2_memctl *)mcontext) = *((pcre2_memctl *)gcontext);
+return mcontext;
+}
+
+
+/* A default convert context is set up to save having to initialize at run time
+when no context is supplied to the convert function. */
+
+const pcre2_convert_context PRIV(default_convert_context) = {
+ { default_malloc, default_free, NULL }, /* Default memory handling */
+#ifdef _WIN32
+ CHAR_BACKSLASH, /* Default path separator */
+ CHAR_GRAVE_ACCENT /* Default escape character */
+#else /* Not Windows */
+ CHAR_SLASH, /* Default path separator */
+ CHAR_BACKSLASH /* Default escape character */
+#endif
+ };
+
+/* The create function copies the default into the new memory, but must
+override the default memory handling functions if a gcontext was provided. */
+
+PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION
+pcre2_convert_context_create(pcre2_general_context *gcontext)
+{
+pcre2_convert_context *ccontext = PRIV(memctl_malloc)(
+ sizeof(pcre2_real_convert_context), (pcre2_memctl *)gcontext);
+if (ccontext == NULL) return NULL;
+*ccontext = PRIV(default_convert_context);
+if (gcontext != NULL)
+ *((pcre2_memctl *)ccontext) = *((pcre2_memctl *)gcontext);
+return ccontext;
+}
+
+
+/*************************************************
+* Context copy functions *
+*************************************************/
+
+PCRE2_EXP_DEFN pcre2_general_context * PCRE2_CALL_CONVENTION
+pcre2_general_context_copy(pcre2_general_context *gcontext)
+{
+pcre2_general_context *new =
+ gcontext->memctl.malloc(sizeof(pcre2_real_general_context),
+ gcontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, gcontext, sizeof(pcre2_real_general_context));
+return new;
+}
+
+
+PCRE2_EXP_DEFN pcre2_compile_context * PCRE2_CALL_CONVENTION
+pcre2_compile_context_copy(pcre2_compile_context *ccontext)
+{
+pcre2_compile_context *new =
+ ccontext->memctl.malloc(sizeof(pcre2_real_compile_context),
+ ccontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, ccontext, sizeof(pcre2_real_compile_context));
+return new;
+}
+
+
+PCRE2_EXP_DEFN pcre2_match_context * PCRE2_CALL_CONVENTION
+pcre2_match_context_copy(pcre2_match_context *mcontext)
+{
+pcre2_match_context *new =
+ mcontext->memctl.malloc(sizeof(pcre2_real_match_context),
+ mcontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, mcontext, sizeof(pcre2_real_match_context));
+return new;
+}
+
+
+
+PCRE2_EXP_DEFN pcre2_convert_context * PCRE2_CALL_CONVENTION
+pcre2_convert_context_copy(pcre2_convert_context *ccontext)
+{
+pcre2_convert_context *new =
+ ccontext->memctl.malloc(sizeof(pcre2_real_convert_context),
+ ccontext->memctl.memory_data);
+if (new == NULL) return NULL;
+memcpy(new, ccontext, sizeof(pcre2_real_convert_context));
+return new;
+}
+
+
+/*************************************************
+* Context free functions *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_general_context_free(pcre2_general_context *gcontext)
+{
+if (gcontext != NULL)
+ gcontext->memctl.free(gcontext, gcontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_compile_context_free(pcre2_compile_context *ccontext)
+{
+if (ccontext != NULL)
+ ccontext->memctl.free(ccontext, ccontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_match_context_free(pcre2_match_context *mcontext)
+{
+if (mcontext != NULL)
+ mcontext->memctl.free(mcontext, mcontext->memctl.memory_data);
+}
+
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_convert_context_free(pcre2_convert_context *ccontext)
+{
+if (ccontext != NULL)
+ ccontext->memctl.free(ccontext, ccontext->memctl.memory_data);
+}
+
+
+/*************************************************
+* Set values in contexts *
+*************************************************/
+
+/* All these functions return 0 for success or PCRE2_ERROR_BADDATA if invalid
+data is given. Only some of the functions are able to test the validity of the
+data. */
+
+
+/* ------------ Compile context ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_character_tables(pcre2_compile_context *ccontext,
+ const unsigned char *tables)
+{
+ccontext->tables = tables;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_bsr(pcre2_compile_context *ccontext, uint32_t value)
+{
+switch(value)
+ {
+ case PCRE2_BSR_ANYCRLF:
+ case PCRE2_BSR_UNICODE:
+ ccontext->bsr_convention = value;
+ return 0;
+
+ default:
+ return PCRE2_ERROR_BADDATA;
+ }
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_max_pattern_length(pcre2_compile_context *ccontext, PCRE2_SIZE length)
+{
+ccontext->max_pattern_length = length;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_newline(pcre2_compile_context *ccontext, uint32_t newline)
+{
+switch(newline)
+ {
+ case PCRE2_NEWLINE_CR:
+ case PCRE2_NEWLINE_LF:
+ case PCRE2_NEWLINE_CRLF:
+ case PCRE2_NEWLINE_ANY:
+ case PCRE2_NEWLINE_ANYCRLF:
+ case PCRE2_NEWLINE_NUL:
+ ccontext->newline_convention = newline;
+ return 0;
+
+ default:
+ return PCRE2_ERROR_BADDATA;
+ }
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_parens_nest_limit(pcre2_compile_context *ccontext, uint32_t limit)
+{
+ccontext->parens_nest_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_compile_extra_options(pcre2_compile_context *ccontext, uint32_t options)
+{
+ccontext->extra_options = options;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_compile_recursion_guard(pcre2_compile_context *ccontext,
+ int (*guard)(uint32_t, void *), void *user_data)
+{
+ccontext->stack_guard = guard;
+ccontext->stack_guard_data = user_data;
+return 0;
+}
+
+
+/* ------------ Match context ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_callout(pcre2_match_context *mcontext,
+ int (*callout)(pcre2_callout_block *, void *), void *callout_data)
+{
+mcontext->callout = callout;
+mcontext->callout_data = callout_data;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_heap_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->heap_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_match_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->match_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_depth_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+mcontext->depth_limit = limit;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_offset_limit(pcre2_match_context *mcontext, PCRE2_SIZE limit)
+{
+mcontext->offset_limit = limit;
+return 0;
+}
+
+/* This function became obsolete at release 10.30. It is kept as a synonym for
+backwards compatibility. */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_recursion_limit(pcre2_match_context *mcontext, uint32_t limit)
+{
+return pcre2_set_depth_limit(mcontext, limit);
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_recursion_memory_management(pcre2_match_context *mcontext,
+ void *(*mymalloc)(size_t, void *), void (*myfree)(void *, void *),
+ void *mydata)
+{
+(void)mcontext;
+(void)mymalloc;
+(void)myfree;
+(void)mydata;
+return 0;
+}
+
+/* ------------ Convert context ------------ */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_glob_separator(pcre2_convert_context *ccontext, uint32_t separator)
+{
+if (separator != CHAR_SLASH && separator != CHAR_BACKSLASH &&
+ separator != CHAR_DOT) return PCRE2_ERROR_BADDATA;
+ccontext->glob_separator = separator;
+return 0;
+}
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_set_glob_escape(pcre2_convert_context *ccontext, uint32_t escape)
+{
+if (escape > 255 || (escape != 0 && !ispunct(escape)))
+ return PCRE2_ERROR_BADDATA;
+ccontext->glob_escape = escape;
+return 0;
+}
+
+/* End of pcre2_context.c */
+
diff --git a/test/monniaux/pcre2-10.32/pcre2_convert.c b/test/monniaux/pcre2-10.32/pcre2_convert.c
new file mode 100644
index 00000000..1dd5c337
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_convert.c
@@ -0,0 +1,1182 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define TYPE_OPTIONS (PCRE2_CONVERT_GLOB| \
+ PCRE2_CONVERT_POSIX_BASIC|PCRE2_CONVERT_POSIX_EXTENDED)
+
+#define ALL_OPTIONS (PCRE2_CONVERT_UTF|PCRE2_CONVERT_NO_UTF_CHECK| \
+ PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR| \
+ PCRE2_CONVERT_GLOB_NO_STARSTAR| \
+ TYPE_OPTIONS)
+
+#define DUMMY_BUFFER_SIZE 100
+
+/* Generated pattern fragments */
+
+#define STR_BACKSLASH_A STR_BACKSLASH STR_A
+#define STR_BACKSLASH_z STR_BACKSLASH STR_z
+#define STR_COLON_RIGHT_SQUARE_BRACKET STR_COLON STR_RIGHT_SQUARE_BRACKET
+#define STR_DOT_STAR_LOOKBEHIND STR_DOT STR_ASTERISK STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_LESS_THAN_SIGN STR_EQUALS_SIGN
+#define STR_LOOKAHEAD_NOT_DOT STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_EXCLAMATION_MARK STR_BACKSLASH STR_DOT STR_RIGHT_PARENTHESIS
+#define STR_QUERY_s STR_LEFT_PARENTHESIS STR_QUESTION_MARK STR_s STR_RIGHT_PARENTHESIS
+#define STR_STAR_NUL STR_LEFT_PARENTHESIS STR_ASTERISK STR_N STR_U STR_L STR_RIGHT_PARENTHESIS
+
+/* States for range and POSIX processing */
+
+enum { RANGE_NOT_STARTED, RANGE_STARTING, RANGE_STARTED };
+enum { POSIX_START_REGEX, POSIX_ANCHORED, POSIX_NOT_BRACKET,
+ POSIX_CLASS_NOT_STARTED, POSIX_CLASS_STARTING, POSIX_CLASS_STARTED };
+
+/* Macro to add a character string to the output buffer, checking for overflow. */
+
+#define PUTCHARS(string) \
+ { \
+ for (s = (char *)(string); *s != 0; s++) \
+ { \
+ if (p >= endp) return PCRE2_ERROR_NOMEMORY; \
+ *p++ = *s; \
+ } \
+ }
+
+/* Literals that must be escaped: \ ? * + | . ^ $ { } [ ] ( ) */
+
+static const char *pcre2_escaped_literals =
+ STR_BACKSLASH STR_QUESTION_MARK STR_ASTERISK STR_PLUS
+ STR_VERTICAL_LINE STR_DOT STR_CIRCUMFLEX_ACCENT STR_DOLLAR_SIGN
+ STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET
+ STR_LEFT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
+ STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS;
+
+/* Recognized escaped metacharacters in POSIX basic patterns. */
+
+static const char *posix_meta_escapes =
+ STR_LEFT_PARENTHESIS STR_RIGHT_PARENTHESIS
+ STR_LEFT_CURLY_BRACKET STR_RIGHT_CURLY_BRACKET
+ STR_1 STR_2 STR_3 STR_4 STR_5 STR_6 STR_7 STR_8 STR_9;
+
+
+
+/*************************************************
+* Convert a POSIX pattern *
+*************************************************/
+
+/* This function handles both basic and extended POSIX patterns.
+
+Arguments:
+ pattype the pattern type
+ pattern the pattern
+ plength length in code units
+ utf TRUE if UTF
+ use_buffer where to put the output
+ use_length length of use_buffer
+ bufflenptr where to put the used length
+ dummyrun TRUE if a dummy run
+ ccontext the convert context
+
+Returns: 0 => success
+ !0 => error code
+*/
+
+static int
+convert_posix(uint32_t pattype, PCRE2_SPTR pattern, PCRE2_SIZE plength,
+ BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length,
+ PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext)
+{
+char *s;
+PCRE2_SPTR posix = pattern;
+PCRE2_UCHAR *p = use_buffer;
+PCRE2_UCHAR *pp = p;
+PCRE2_UCHAR *endp = p + use_length - 1; /* Allow for trailing zero */
+PCRE2_SIZE convlength = 0;
+
+uint32_t bracount = 0;
+uint32_t posix_state = POSIX_START_REGEX;
+uint32_t lastspecial = 0;
+BOOL extended = (pattype & PCRE2_CONVERT_POSIX_EXTENDED) != 0;
+BOOL nextisliteral = FALSE;
+
+(void)utf; /* Not used when Unicode not supported */
+(void)ccontext; /* Not currently used */
+
+/* Initialize default for error offset as end of input. */
+
+*bufflenptr = plength;
+PUTCHARS(STR_STAR_NUL);
+
+/* Now scan the input. */
+
+while (plength > 0)
+ {
+ uint32_t c, sc;
+ int clength = 1;
+
+ /* Add in the length of the last item, then, if in the dummy run, pull the
+ pointer back to the start of the (temporary) buffer and then remember the
+ start of the next item. */
+
+ convlength += p - pp;
+ if (dummyrun) p = use_buffer;
+ pp = p;
+
+ /* Pick up the next character */
+
+#ifndef SUPPORT_UNICODE
+ c = *posix;
+#else
+ GETCHARLENTEST(c, posix, clength);
+#endif
+ posix += clength;
+ plength -= clength;
+
+ sc = nextisliteral? 0 : c;
+ nextisliteral = FALSE;
+
+ /* Handle a character within a class. */
+
+ if (posix_state >= POSIX_CLASS_NOT_STARTED)
+ {
+ if (c == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ PUTCHARS(STR_RIGHT_SQUARE_BRACKET);
+ posix_state = POSIX_NOT_BRACKET;
+ }
+
+ /* Not the end of the class */
+
+ else
+ {
+ switch (posix_state)
+ {
+ case POSIX_CLASS_STARTED:
+ if (c <= 127 && islower(c)) break; /* Remain in started state */
+ posix_state = POSIX_CLASS_NOT_STARTED;
+ if (c == CHAR_COLON && plength > 0 &&
+ *posix == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ PUTCHARS(STR_COLON_RIGHT_SQUARE_BRACKET);
+ plength--;
+ posix++;
+ continue; /* With next character after :] */
+ }
+ /* Fall through */
+
+ case POSIX_CLASS_NOT_STARTED:
+ if (c == CHAR_LEFT_SQUARE_BRACKET)
+ posix_state = POSIX_CLASS_STARTING;
+ break;
+
+ case POSIX_CLASS_STARTING:
+ if (c == CHAR_COLON) posix_state = POSIX_CLASS_STARTED;
+ break;
+ }
+
+ if (c == CHAR_BACKSLASH) PUTCHARS(STR_BACKSLASH);
+ if (p + clength > endp) return PCRE2_ERROR_NOMEMORY;
+ memcpy(p, posix - clength, CU2BYTES(clength));
+ p += clength;
+ }
+ }
+
+ /* Handle a character not within a class. */
+
+ else switch(sc)
+ {
+ case CHAR_LEFT_SQUARE_BRACKET:
+ PUTCHARS(STR_LEFT_SQUARE_BRACKET);
+
+#ifdef NEVER
+ /* We could handle special cases [[:<:]] and [[:>:]] (which PCRE does
+ support) but they are not part of POSIX 1003.1. */
+
+ if (plength >= 6)
+ {
+ if (posix[0] == CHAR_LEFT_SQUARE_BRACKET &&
+ posix[1] == CHAR_COLON &&
+ (posix[2] == CHAR_LESS_THAN_SIGN ||
+ posix[2] == CHAR_GREATER_THAN_SIGN) &&
+ posix[3] == CHAR_COLON &&
+ posix[4] == CHAR_RIGHT_SQUARE_BRACKET &&
+ posix[5] == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ if (p + 6 > endp) return PCRE2_ERROR_NOMEMORY;
+ memcpy(p, posix, CU2BYTES(6));
+ p += 6;
+ posix += 6;
+ plength -= 6;
+ continue; /* With next character */
+ }
+ }
+#endif
+
+ /* Handle start of "normal" character classes */
+
+ posix_state = POSIX_CLASS_NOT_STARTED;
+
+ /* Handle ^ and ] as first characters */
+
+ if (plength > 0)
+ {
+ if (*posix == CHAR_CIRCUMFLEX_ACCENT)
+ {
+ posix++;
+ plength--;
+ PUTCHARS(STR_CIRCUMFLEX_ACCENT);
+ }
+ if (plength > 0 && *posix == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ posix++;
+ plength--;
+ PUTCHARS(STR_RIGHT_SQUARE_BRACKET);
+ }
+ }
+ break;
+
+ case CHAR_BACKSLASH:
+ if (plength <= 0) return PCRE2_ERROR_END_BACKSLASH;
+ if (extended) nextisliteral = TRUE; else
+ {
+ if (*posix < 127 && strchr(posix_meta_escapes, *posix) != NULL)
+ {
+ if (isdigit(*posix)) PUTCHARS(STR_BACKSLASH);
+ if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
+ lastspecial = *p++ = *posix++;
+ plength--;
+ }
+ else nextisliteral = TRUE;
+ }
+ break;
+
+ case CHAR_RIGHT_PARENTHESIS:
+ if (!extended || bracount == 0) goto ESCAPE_LITERAL;
+ bracount--;
+ goto COPY_SPECIAL;
+
+ case CHAR_LEFT_PARENTHESIS:
+ bracount++;
+ /* Fall through */
+
+ case CHAR_QUESTION_MARK:
+ case CHAR_PLUS:
+ case CHAR_LEFT_CURLY_BRACKET:
+ case CHAR_RIGHT_CURLY_BRACKET:
+ case CHAR_VERTICAL_LINE:
+ if (!extended) goto ESCAPE_LITERAL;
+ /* Fall through */
+
+ case CHAR_DOT:
+ case CHAR_DOLLAR_SIGN:
+ posix_state = POSIX_NOT_BRACKET;
+ COPY_SPECIAL:
+ lastspecial = c;
+ if (p + 1 > endp) return PCRE2_ERROR_NOMEMORY;
+ *p++ = c;
+ break;
+
+ case CHAR_ASTERISK:
+ if (lastspecial != CHAR_ASTERISK)
+ {
+ if (!extended && (posix_state < POSIX_NOT_BRACKET ||
+ lastspecial == CHAR_LEFT_PARENTHESIS))
+ goto ESCAPE_LITERAL;
+ goto COPY_SPECIAL;
+ }
+ break; /* Ignore second and subsequent asterisks */
+
+ case CHAR_CIRCUMFLEX_ACCENT:
+ if (extended) goto COPY_SPECIAL;
+ if (posix_state == POSIX_START_REGEX ||
+ lastspecial == CHAR_LEFT_PARENTHESIS)
+ {
+ posix_state = POSIX_ANCHORED;
+ goto COPY_SPECIAL;
+ }
+ /* Fall through */
+
+ default:
+ if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
+ {
+ ESCAPE_LITERAL:
+ PUTCHARS(STR_BACKSLASH);
+ }
+ lastspecial = 0xff; /* Indicates nothing special */
+ if (p + clength > endp) return PCRE2_ERROR_NOMEMORY;
+ memcpy(p, posix - clength, CU2BYTES(clength));
+ p += clength;
+ posix_state = POSIX_NOT_BRACKET;
+ break;
+ }
+ }
+
+if (posix_state >= POSIX_CLASS_NOT_STARTED)
+ return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+convlength += p - pp; /* Final segment */
+*bufflenptr = convlength;
+*p++ = 0;
+return 0;
+}
+
+
+/*************************************************
+* Convert a glob pattern *
+*************************************************/
+
+/* Context for writing the output into a buffer. */
+
+typedef struct pcre2_output_context {
+ PCRE2_UCHAR *output; /* current output position */
+ PCRE2_SPTR output_end; /* output end */
+ PCRE2_SIZE output_size; /* size of the output */
+ uint8_t out_str[8]; /* string copied to the output */
+} pcre2_output_context;
+
+
+/* Write a character into the output.
+
+Arguments:
+ out output context
+ chr the next character
+*/
+
+static void
+convert_glob_write(pcre2_output_context *out, PCRE2_UCHAR chr)
+{
+out->output_size++;
+
+if (out->output < out->output_end)
+ *out->output++ = chr;
+}
+
+
+/* Write a string into the output.
+
+Arguments:
+ out output context
+ length length of out->out_str
+*/
+
+static void
+convert_glob_write_str(pcre2_output_context *out, PCRE2_SIZE length)
+{
+uint8_t *out_str = out->out_str;
+PCRE2_UCHAR *output = out->output;
+PCRE2_SPTR output_end = out->output_end;
+PCRE2_SIZE output_size = out->output_size;
+
+do
+ {
+ output_size++;
+
+ if (output < output_end)
+ *output++ = *out_str++;
+ }
+while (--length != 0);
+
+out->output = output;
+out->output_size = output_size;
+}
+
+
+/* Prints the separator into the output.
+
+Arguments:
+ out output context
+ separator glob separator
+ with_escape backslash is needed before separator
+*/
+
+static void
+convert_glob_print_separator(pcre2_output_context *out,
+ PCRE2_UCHAR separator, BOOL with_escape)
+{
+if (with_escape)
+ convert_glob_write(out, CHAR_BACKSLASH);
+
+convert_glob_write(out, separator);
+}
+
+
+/* Prints a wildcard into the output.
+
+Arguments:
+ out output context
+ separator glob separator
+ with_escape backslash is needed before separator
+*/
+
+static void
+convert_glob_print_wildcard(pcre2_output_context *out,
+ PCRE2_UCHAR separator, BOOL with_escape)
+{
+out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET;
+out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT;
+convert_glob_write_str(out, 2);
+
+convert_glob_print_separator(out, separator, with_escape);
+
+convert_glob_write(out, CHAR_RIGHT_SQUARE_BRACKET);
+}
+
+
+/* Parse a posix class.
+
+Arguments:
+ from starting point of scanning the range
+ pattern_end end of pattern
+ out output context
+
+Returns: >0 => class index
+ 0 => malformed class
+*/
+
+static int
+convert_glob_parse_class(PCRE2_SPTR *from, PCRE2_SPTR pattern_end,
+ pcre2_output_context *out)
+{
+static const char *posix_classes = "alnum:alpha:ascii:blank:cntrl:digit:"
+ "graph:lower:print:punct:space:upper:word:xdigit:";
+PCRE2_SPTR start = *from + 1;
+PCRE2_SPTR pattern = start;
+const char *class_ptr;
+PCRE2_UCHAR c;
+int class_index;
+
+while (TRUE)
+ {
+ if (pattern >= pattern_end) return 0;
+
+ c = *pattern++;
+
+ if (c < CHAR_a || c > CHAR_z) break;
+ }
+
+if (c != CHAR_COLON || pattern >= pattern_end ||
+ *pattern != CHAR_RIGHT_SQUARE_BRACKET)
+ return 0;
+
+class_ptr = posix_classes;
+class_index = 1;
+
+while (TRUE)
+ {
+ if (*class_ptr == CHAR_NUL) return 0;
+
+ pattern = start;
+
+ while (*pattern == (PCRE2_UCHAR) *class_ptr)
+ {
+ if (*pattern == CHAR_COLON)
+ {
+ pattern += 2;
+ start -= 2;
+
+ do convert_glob_write(out, *start++); while (start < pattern);
+
+ *from = pattern;
+ return class_index;
+ }
+ pattern++;
+ class_ptr++;
+ }
+
+ while (*class_ptr != CHAR_COLON) class_ptr++;
+ class_ptr++;
+ class_index++;
+ }
+}
+
+/* Checks whether the character is in the class.
+
+Arguments:
+ class_index class index
+ c character
+
+Returns: !0 => character is found in the class
+ 0 => otherwise
+*/
+
+static BOOL
+convert_glob_char_in_class(int class_index, PCRE2_UCHAR c)
+{
+switch (class_index)
+ {
+ case 1: return isalnum(c);
+ case 2: return isalpha(c);
+ case 3: return 1;
+ case 4: return c == CHAR_HT || c == CHAR_SPACE;
+ case 5: return iscntrl(c);
+ case 6: return isdigit(c);
+ case 7: return isgraph(c);
+ case 8: return islower(c);
+ case 9: return isprint(c);
+ case 10: return ispunct(c);
+ case 11: return isspace(c);
+ case 12: return isupper(c);
+ case 13: return isalnum(c) || c == CHAR_UNDERSCORE;
+ default: return isxdigit(c);
+ }
+}
+
+/* Parse a range of characters.
+
+Arguments:
+ from starting point of scanning the range
+ pattern_end end of pattern
+ out output context
+ separator glob separator
+ with_escape backslash is needed before separator
+
+Returns: 0 => success
+ !0 => error code
+*/
+
+static int
+convert_glob_parse_range(PCRE2_SPTR *from, PCRE2_SPTR pattern_end,
+ pcre2_output_context *out, BOOL utf, PCRE2_UCHAR separator,
+ BOOL with_escape, PCRE2_UCHAR escape, BOOL no_wildsep)
+{
+BOOL is_negative = FALSE;
+BOOL separator_seen = FALSE;
+BOOL has_prev_c;
+PCRE2_SPTR pattern = *from;
+PCRE2_SPTR char_start = NULL;
+uint32_t c, prev_c;
+int len, class_index;
+
+(void)utf; /* Avoid compiler warning. */
+
+if (pattern >= pattern_end)
+ {
+ *from = pattern;
+ return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+ }
+
+if (*pattern == CHAR_EXCLAMATION_MARK
+ || *pattern == CHAR_CIRCUMFLEX_ACCENT)
+ {
+ pattern++;
+
+ if (pattern >= pattern_end)
+ {
+ *from = pattern;
+ return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+ }
+
+ is_negative = TRUE;
+
+ out->out_str[0] = CHAR_LEFT_SQUARE_BRACKET;
+ out->out_str[1] = CHAR_CIRCUMFLEX_ACCENT;
+ len = 2;
+
+ if (!no_wildsep)
+ {
+ if (with_escape)
+ {
+ out->out_str[len] = CHAR_BACKSLASH;
+ len++;
+ }
+ out->out_str[len] = (uint8_t) separator;
+ }
+
+ convert_glob_write_str(out, len + 1);
+ }
+else
+ convert_glob_write(out, CHAR_LEFT_SQUARE_BRACKET);
+
+has_prev_c = FALSE;
+prev_c = 0;
+
+if (*pattern == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ out->out_str[0] = CHAR_BACKSLASH;
+ out->out_str[1] = CHAR_RIGHT_SQUARE_BRACKET;
+ convert_glob_write_str(out, 2);
+ has_prev_c = TRUE;
+ prev_c = CHAR_RIGHT_SQUARE_BRACKET;
+ pattern++;
+ }
+
+while (pattern < pattern_end)
+ {
+ char_start = pattern;
+ GETCHARINCTEST(c, pattern);
+
+ if (c == CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ convert_glob_write(out, c);
+
+ if (!is_negative && !no_wildsep && separator_seen)
+ {
+ out->out_str[0] = CHAR_LEFT_PARENTHESIS;
+ out->out_str[1] = CHAR_QUESTION_MARK;
+ out->out_str[2] = CHAR_LESS_THAN_SIGN;
+ out->out_str[3] = CHAR_EXCLAMATION_MARK;
+ convert_glob_write_str(out, 4);
+
+ convert_glob_print_separator(out, separator, with_escape);
+ convert_glob_write(out, CHAR_RIGHT_PARENTHESIS);
+ }
+
+ *from = pattern;
+ return 0;
+ }
+
+ if (pattern >= pattern_end) break;
+
+ if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON)
+ {
+ *from = pattern;
+ class_index = convert_glob_parse_class(from, pattern_end, out);
+
+ if (class_index != 0)
+ {
+ pattern = *from;
+
+ has_prev_c = FALSE;
+ prev_c = 0;
+
+ if (!is_negative &&
+ convert_glob_char_in_class (class_index, separator))
+ separator_seen = TRUE;
+ continue;
+ }
+ }
+ else if (c == CHAR_MINUS && has_prev_c &&
+ *pattern != CHAR_RIGHT_SQUARE_BRACKET)
+ {
+ convert_glob_write(out, CHAR_MINUS);
+
+ char_start = pattern;
+ GETCHARINCTEST(c, pattern);
+
+ if (pattern >= pattern_end) break;
+
+ if (escape != 0 && c == escape)
+ {
+ char_start = pattern;
+ GETCHARINCTEST(c, pattern);
+ }
+ else if (c == CHAR_LEFT_SQUARE_BRACKET && *pattern == CHAR_COLON)
+ {
+ *from = pattern;
+ return PCRE2_ERROR_CONVERT_SYNTAX;
+ }
+
+ if (prev_c > c)
+ {
+ *from = pattern;
+ return PCRE2_ERROR_CONVERT_SYNTAX;
+ }
+
+ if (prev_c < separator && separator < c) separator_seen = TRUE;
+
+ has_prev_c = FALSE;
+ prev_c = 0;
+ }
+ else
+ {
+ if (escape != 0 && c == escape)
+ {
+ char_start = pattern;
+ GETCHARINCTEST(c, pattern);
+
+ if (pattern >= pattern_end) break;
+ }
+
+ has_prev_c = TRUE;
+ prev_c = c;
+ }
+
+ if (c == CHAR_LEFT_SQUARE_BRACKET || c == CHAR_RIGHT_SQUARE_BRACKET ||
+ c == CHAR_BACKSLASH || c == CHAR_MINUS)
+ convert_glob_write(out, CHAR_BACKSLASH);
+
+ if (c == separator) separator_seen = TRUE;
+
+ do convert_glob_write(out, *char_start++); while (char_start < pattern);
+ }
+
+*from = pattern;
+return PCRE2_ERROR_MISSING_SQUARE_BRACKET;
+}
+
+
+/* Prints a (*COMMIT) into the output.
+
+Arguments:
+ out output context
+*/
+
+static void
+convert_glob_print_commit(pcre2_output_context *out)
+{
+out->out_str[0] = CHAR_LEFT_PARENTHESIS;
+out->out_str[1] = CHAR_ASTERISK;
+out->out_str[2] = CHAR_C;
+out->out_str[3] = CHAR_O;
+out->out_str[4] = CHAR_M;
+out->out_str[5] = CHAR_M;
+out->out_str[6] = CHAR_I;
+out->out_str[7] = CHAR_T;
+convert_glob_write_str(out, 8);
+convert_glob_write(out, CHAR_RIGHT_PARENTHESIS);
+}
+
+
+/* Bash glob converter.
+
+Arguments:
+ pattype the pattern type
+ pattern the pattern
+ plength length in code units
+ utf TRUE if UTF
+ use_buffer where to put the output
+ use_length length of use_buffer
+ bufflenptr where to put the used length
+ dummyrun TRUE if a dummy run
+ ccontext the convert context
+
+Returns: 0 => success
+ !0 => error code
+*/
+
+static int
+convert_glob(uint32_t options, PCRE2_SPTR pattern, PCRE2_SIZE plength,
+ BOOL utf, PCRE2_UCHAR *use_buffer, PCRE2_SIZE use_length,
+ PCRE2_SIZE *bufflenptr, BOOL dummyrun, pcre2_convert_context *ccontext)
+{
+pcre2_output_context out;
+PCRE2_SPTR pattern_start = pattern;
+PCRE2_SPTR pattern_end = pattern + plength;
+PCRE2_UCHAR separator = ccontext->glob_separator;
+PCRE2_UCHAR escape = ccontext->glob_escape;
+PCRE2_UCHAR c;
+BOOL no_wildsep = (options & PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR) != 0;
+BOOL no_starstar = (options & PCRE2_CONVERT_GLOB_NO_STARSTAR) != 0;
+BOOL in_atomic = FALSE;
+BOOL after_starstar = FALSE;
+BOOL no_slash_z = FALSE;
+BOOL with_escape, is_start, after_separator;
+int result = 0;
+
+(void)utf; /* Avoid compiler warning. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (separator >= 128 || escape >= 128))
+ {
+ /* Currently only ASCII characters are supported. */
+ *bufflenptr = 0;
+ return PCRE2_ERROR_CONVERT_SYNTAX;
+ }
+#endif
+
+with_escape = strchr(pcre2_escaped_literals, separator) != NULL;
+
+/* Initialize default for error offset as end of input. */
+out.output = use_buffer;
+out.output_end = use_buffer + use_length;
+out.output_size = 0;
+
+out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+out.out_str[1] = CHAR_QUESTION_MARK;
+out.out_str[2] = CHAR_s;
+out.out_str[3] = CHAR_RIGHT_PARENTHESIS;
+convert_glob_write_str(&out, 4);
+
+is_start = TRUE;
+
+if (pattern < pattern_end && pattern[0] == CHAR_ASTERISK)
+ {
+ if (no_wildsep)
+ is_start = FALSE;
+ else if (!no_starstar && pattern + 1 < pattern_end &&
+ pattern[1] == CHAR_ASTERISK)
+ is_start = FALSE;
+ }
+
+if (is_start)
+ {
+ out.out_str[0] = CHAR_BACKSLASH;
+ out.out_str[1] = CHAR_A;
+ convert_glob_write_str(&out, 2);
+ }
+
+while (pattern < pattern_end)
+ {
+ c = *pattern++;
+
+ if (c == CHAR_ASTERISK)
+ {
+ is_start = pattern == pattern_start + 1;
+
+ if (in_atomic)
+ {
+ convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
+ in_atomic = FALSE;
+ }
+
+ if (!no_starstar && pattern < pattern_end && *pattern == CHAR_ASTERISK)
+ {
+ after_separator = is_start || (pattern[-2] == separator);
+
+ do pattern++; while (pattern < pattern_end &&
+ *pattern == CHAR_ASTERISK);
+
+ if (pattern >= pattern_end)
+ {
+ no_slash_z = TRUE;
+ break;
+ }
+
+ after_starstar = TRUE;
+
+ if (after_separator && escape != 0 && *pattern == escape &&
+ pattern + 1 < pattern_end && pattern[1] == separator)
+ pattern++;
+
+ if (is_start)
+ {
+ if (*pattern != separator) continue;
+
+ out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+ out.out_str[1] = CHAR_QUESTION_MARK;
+ out.out_str[2] = CHAR_COLON;
+ out.out_str[3] = CHAR_BACKSLASH;
+ out.out_str[4] = CHAR_A;
+ out.out_str[5] = CHAR_VERTICAL_LINE;
+ convert_glob_write_str(&out, 6);
+
+ convert_glob_print_separator(&out, separator, with_escape);
+ convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
+
+ pattern++;
+ continue;
+ }
+
+ convert_glob_print_commit(&out);
+
+ if (!after_separator || *pattern != separator)
+ {
+ out.out_str[0] = CHAR_DOT;
+ out.out_str[1] = CHAR_ASTERISK;
+ out.out_str[2] = CHAR_QUESTION_MARK;
+ convert_glob_write_str(&out, 3);
+ continue;
+ }
+
+ out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+ out.out_str[1] = CHAR_QUESTION_MARK;
+ out.out_str[2] = CHAR_COLON;
+ out.out_str[3] = CHAR_DOT;
+ out.out_str[4] = CHAR_ASTERISK;
+ out.out_str[5] = CHAR_QUESTION_MARK;
+
+ convert_glob_write_str(&out, 6);
+
+ convert_glob_print_separator(&out, separator, with_escape);
+
+ out.out_str[0] = CHAR_RIGHT_PARENTHESIS;
+ out.out_str[1] = CHAR_QUESTION_MARK;
+ out.out_str[2] = CHAR_QUESTION_MARK;
+ convert_glob_write_str(&out, 3);
+
+ pattern++;
+ continue;
+ }
+
+ if (pattern < pattern_end && *pattern == CHAR_ASTERISK)
+ {
+ do pattern++; while (pattern < pattern_end &&
+ *pattern == CHAR_ASTERISK);
+ }
+
+ if (no_wildsep)
+ {
+ if (pattern >= pattern_end)
+ {
+ no_slash_z = TRUE;
+ break;
+ }
+
+ /* Start check must be after the end check. */
+ if (is_start) continue;
+ }
+
+ if (!is_start)
+ {
+ if (after_starstar)
+ {
+ out.out_str[0] = CHAR_LEFT_PARENTHESIS;
+ out.out_str[1] = CHAR_QUESTION_MARK;
+ out.out_str[2] = CHAR_GREATER_THAN_SIGN;
+ convert_glob_write_str(&out, 3);
+ in_atomic = TRUE;
+ }
+ else
+ convert_glob_print_commit(&out);
+ }
+
+ if (no_wildsep)
+ convert_glob_write(&out, CHAR_DOT);
+ else
+ convert_glob_print_wildcard(&out, separator, with_escape);
+
+ out.out_str[0] = CHAR_ASTERISK;
+ out.out_str[1] = CHAR_QUESTION_MARK;
+ if (pattern >= pattern_end)
+ out.out_str[1] = CHAR_PLUS;
+ convert_glob_write_str(&out, 2);
+ continue;
+ }
+
+ if (c == CHAR_QUESTION_MARK)
+ {
+ if (no_wildsep)
+ convert_glob_write(&out, CHAR_DOT);
+ else
+ convert_glob_print_wildcard(&out, separator, with_escape);
+ continue;
+ }
+
+ if (c == CHAR_LEFT_SQUARE_BRACKET)
+ {
+ result = convert_glob_parse_range(&pattern, pattern_end,
+ &out, utf, separator, with_escape, escape, no_wildsep);
+ if (result != 0) break;
+ continue;
+ }
+
+ if (escape != 0 && c == escape)
+ {
+ if (pattern >= pattern_end)
+ {
+ result = PCRE2_ERROR_CONVERT_SYNTAX;
+ break;
+ }
+ c = *pattern++;
+ }
+
+ if (c < 128 && strchr(pcre2_escaped_literals, c) != NULL)
+ convert_glob_write(&out, CHAR_BACKSLASH);
+
+ convert_glob_write(&out, c);
+ }
+
+if (result == 0)
+ {
+ if (!no_slash_z)
+ {
+ out.out_str[0] = CHAR_BACKSLASH;
+ out.out_str[1] = CHAR_z;
+ convert_glob_write_str(&out, 2);
+ }
+
+ if (in_atomic)
+ convert_glob_write(&out, CHAR_RIGHT_PARENTHESIS);
+
+ convert_glob_write(&out, CHAR_NUL);
+
+ if (!dummyrun && out.output_size != (PCRE2_SIZE) (out.output - use_buffer))
+ result = PCRE2_ERROR_NOMEMORY;
+ }
+
+if (result != 0)
+ {
+ *bufflenptr = pattern - pattern_start;
+ return result;
+ }
+
+*bufflenptr = out.output_size - 1;
+return 0;
+}
+
+
+/*************************************************
+* Convert pattern *
+*************************************************/
+
+/* This is the external-facing function for converting other forms of pattern
+into PCRE2 regular expression patterns. On error, the bufflenptr argument is
+used to return an offset in the original pattern.
+
+Arguments:
+ pattern the input pattern
+ plength length of input, or PCRE2_ZERO_TERMINATED
+ options options bits
+ buffptr pointer to pointer to output buffer
+ bufflenptr pointer to length of output buffer
+ ccontext convert context or NULL
+
+Returns: 0 for success, else an error code (+ve or -ve)
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_pattern_convert(PCRE2_SPTR pattern, PCRE2_SIZE plength, uint32_t options,
+ PCRE2_UCHAR **buffptr, PCRE2_SIZE *bufflenptr,
+ pcre2_convert_context *ccontext)
+{
+int i, rc;
+PCRE2_UCHAR dummy_buffer[DUMMY_BUFFER_SIZE];
+PCRE2_UCHAR *use_buffer = dummy_buffer;
+PCRE2_SIZE use_length = DUMMY_BUFFER_SIZE;
+BOOL utf = (options & PCRE2_CONVERT_UTF) != 0;
+uint32_t pattype = options & TYPE_OPTIONS;
+
+if (pattern == NULL || bufflenptr == NULL) return PCRE2_ERROR_NULL;
+
+if ((options & ~ALL_OPTIONS) != 0 || /* Undefined bit set */
+ (pattype & (~pattype+1)) != pattype || /* More than one type set */
+ pattype == 0) /* No type set */
+ {
+ *bufflenptr = 0; /* Error offset */
+ return PCRE2_ERROR_BADOPTION;
+ }
+
+if (plength == PCRE2_ZERO_TERMINATED) plength = PRIV(strlen)(pattern);
+if (ccontext == NULL) ccontext =
+ (pcre2_convert_context *)(&PRIV(default_convert_context));
+
+/* Check UTF if required. */
+
+#ifndef SUPPORT_UNICODE
+if (utf)
+ {
+ *bufflenptr = 0; /* Error offset */
+ return PCRE2_ERROR_UNICODE_NOT_SUPPORTED;
+ }
+#else
+if (utf && (options & PCRE2_CONVERT_NO_UTF_CHECK) == 0)
+ {
+ PCRE2_SIZE erroroffset;
+ rc = PRIV(valid_utf)(pattern, plength, &erroroffset);
+ if (rc != 0)
+ {
+ *bufflenptr = erroroffset;
+ return rc;
+ }
+ }
+#endif
+
+/* If buffptr is not NULL, and what it points to is not NULL, we are being
+provided with a buffer and a length, so set them as the buffer to use. */
+
+if (buffptr != NULL && *buffptr != NULL)
+ {
+ use_buffer = *buffptr;
+ use_length = *bufflenptr;
+ }
+
+/* Call an individual converter, either just once (if a buffer was provided or
+just the length is needed), or twice (if a memory allocation is required). */
+
+for (i = 0; i < 2; i++)
+ {
+ PCRE2_UCHAR *allocated;
+ BOOL dummyrun = buffptr == NULL || *buffptr == NULL;
+
+ switch(pattype)
+ {
+ case PCRE2_CONVERT_GLOB:
+ rc = convert_glob(options & ~PCRE2_CONVERT_GLOB, pattern, plength, utf,
+ use_buffer, use_length, bufflenptr, dummyrun, ccontext);
+ break;
+
+ case PCRE2_CONVERT_POSIX_BASIC:
+ case PCRE2_CONVERT_POSIX_EXTENDED:
+ rc = convert_posix(pattype, pattern, plength, utf, use_buffer, use_length,
+ bufflenptr, dummyrun, ccontext);
+ break;
+
+ default:
+ *bufflenptr = 0; /* Error offset */
+ return PCRE2_ERROR_INTERNAL;
+ }
+
+ if (rc != 0 || /* Error */
+ buffptr == NULL || /* Just the length is required */
+ *buffptr != NULL) /* Buffer was provided or allocated */
+ return rc;
+
+ /* Allocate memory for the buffer, with hidden space for an allocator at
+ the start. The next time round the loop runs the conversion for real. */
+
+ allocated = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+ (*bufflenptr + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)ccontext);
+ if (allocated == NULL) return PCRE2_ERROR_NOMEMORY;
+ *buffptr = (PCRE2_UCHAR *)(((char *)allocated) + sizeof(pcre2_memctl));
+
+ use_buffer = *buffptr;
+ use_length = *bufflenptr + 1;
+ }
+
+/* Control should never get here. */
+
+return PCRE2_ERROR_INTERNAL;
+}
+
+
+/*************************************************
+* Free converted pattern *
+*************************************************/
+
+/* This frees a converted pattern that was put in newly-allocated memory.
+
+Argument: the converted pattern
+Returns: nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_converted_pattern_free(PCRE2_UCHAR *converted)
+{
+if (converted != NULL)
+ {
+ pcre2_memctl *memctl =
+ (pcre2_memctl *)((char *)converted - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+/* End of pcre2_convert.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_dfa_match.c b/test/monniaux/pcre2-10.32/pcre2_dfa_match.c
new file mode 100644
index 00000000..9b43237d
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_dfa_match.c
@@ -0,0 +1,3864 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains the external function pcre2_dfa_match(), which is an
+alternative matching function that uses a sort of DFA algorithm (not a true
+FSM). This is NOT Perl-compatible, but it has advantages in certain
+applications. */
+
+
+/* NOTE ABOUT PERFORMANCE: A user of this function sent some code that improved
+the performance of his patterns greatly. I could not use it as it stood, as it
+was not thread safe, and made assumptions about pattern sizes. Also, it caused
+test 7 to loop, and test 9 to crash with a segfault.
+
+The issue is the check for duplicate states, which is done by a simple linear
+search up the state list. (Grep for "duplicate" below to find the code.) For
+many patterns, there will never be many states active at one time, so a simple
+linear search is fine. In patterns that have many active states, it might be a
+bottleneck. The suggested code used an indexing scheme to remember which states
+had previously been used for each character, and avoided the linear search when
+it knew there was no chance of a duplicate. This was implemented when adding
+states to the state lists.
+
+I wrote some thread-safe, not-limited code to try something similar at the time
+of checking for duplicates (instead of when adding states), using index vectors
+on the stack. It did give a 13% improvement with one specially constructed
+pattern for certain subject strings, but on other strings and on many of the
+simpler patterns in the test suite it did worse. The major problem, I think,
+was the extra time to initialize the index. This had to be done for each call
+of internal_dfa_match(). (The supplied patch used a static vector, initialized
+only once - I suspect this was the cause of the problems with the tests.)
+
+Overall, I concluded that the gains in some cases did not outweigh the losses
+in others, so I abandoned this code. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define NLBLOCK mb /* Block containing newline information */
+#define PSSTART start_subject /* Field containing processed string start */
+#define PSEND end_subject /* Field containing processed string end */
+
+#include "pcre2_internal.h"
+
+#define PUBLIC_DFA_MATCH_OPTIONS \
+ (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+ PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
+ PCRE2_PARTIAL_SOFT|PCRE2_DFA_SHORTEST|PCRE2_DFA_RESTART)
+
+
+/*************************************************
+* Code parameters and static tables *
+*************************************************/
+
+/* These are offsets that are used to turn the OP_TYPESTAR and friends opcodes
+into others, under special conditions. A gap of 20 between the blocks should be
+enough. The resulting opcodes don't have to be less than 256 because they are
+never stored, so we push them well clear of the normal opcodes. */
+
+#define OP_PROP_EXTRA 300
+#define OP_EXTUNI_EXTRA 320
+#define OP_ANYNL_EXTRA 340
+#define OP_HSPACE_EXTRA 360
+#define OP_VSPACE_EXTRA 380
+
+
+/* This table identifies those opcodes that are followed immediately by a
+character that is to be tested in some way. This makes it possible to
+centralize the loading of these characters. In the case of Type * etc, the
+"character" is the opcode for \D, \d, \S, \s, \W, or \w, which will always be a
+small value. Non-zero values in the table are the offsets from the opcode where
+the character is to be found. ***NOTE*** If the start of this table is
+modified, the three tables that follow must also be modified. */
+
+static const uint8_t coptable[] = {
+ 0, /* End */
+ 0, 0, 0, 0, 0, /* \A, \G, \K, \B, \b */
+ 0, 0, 0, 0, 0, 0, /* \D, \d, \S, \s, \W, \w */
+ 0, 0, 0, /* Any, AllAny, Anybyte */
+ 0, 0, /* \P, \p */
+ 0, 0, 0, 0, 0, /* \R, \H, \h, \V, \v */
+ 0, /* \X */
+ 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */
+ 1, /* Char */
+ 1, /* Chari */
+ 1, /* not */
+ 1, /* noti */
+ /* Positive single-char repeats */
+ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */
+ 1+IMM2_SIZE, 1+IMM2_SIZE, /* upto, minupto */
+ 1+IMM2_SIZE, /* exact */
+ 1, 1, 1, 1+IMM2_SIZE, /* *+, ++, ?+, upto+ */
+ 1, 1, 1, 1, 1, 1, /* *I, *?I, +I, +?I, ?I, ??I */
+ 1+IMM2_SIZE, 1+IMM2_SIZE, /* upto I, minupto I */
+ 1+IMM2_SIZE, /* exact I */
+ 1, 1, 1, 1+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I */
+ /* Negative single-char repeats - only for chars < 256 */
+ 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */
+ 1+IMM2_SIZE, 1+IMM2_SIZE, /* NOT upto, minupto */
+ 1+IMM2_SIZE, /* NOT exact */
+ 1, 1, 1, 1+IMM2_SIZE, /* NOT *+, ++, ?+, upto+ */
+ 1, 1, 1, 1, 1, 1, /* NOT *I, *?I, +I, +?I, ?I, ??I */
+ 1+IMM2_SIZE, 1+IMM2_SIZE, /* NOT upto I, minupto I */
+ 1+IMM2_SIZE, /* NOT exact I */
+ 1, 1, 1, 1+IMM2_SIZE, /* NOT *+I, ++I, ?+I, upto+I */
+ /* Positive type repeats */
+ 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */
+ 1+IMM2_SIZE, 1+IMM2_SIZE, /* Type upto, minupto */
+ 1+IMM2_SIZE, /* Type exact */
+ 1, 1, 1, 1+IMM2_SIZE, /* Type *+, ++, ?+, upto+ */
+ /* Character class & ref repeats */
+ 0, 0, 0, 0, 0, 0, /* *, *?, +, +?, ?, ?? */
+ 0, 0, /* CRRANGE, CRMINRANGE */
+ 0, 0, 0, 0, /* Possessive *+, ++, ?+, CRPOSRANGE */
+ 0, /* CLASS */
+ 0, /* NCLASS */
+ 0, /* XCLASS - variable length */
+ 0, /* REF */
+ 0, /* REFI */
+ 0, /* DNREF */
+ 0, /* DNREFI */
+ 0, /* RECURSE */
+ 0, /* CALLOUT */
+ 0, /* CALLOUT_STR */
+ 0, /* Alt */
+ 0, /* Ket */
+ 0, /* KetRmax */
+ 0, /* KetRmin */
+ 0, /* KetRpos */
+ 0, /* Reverse */
+ 0, /* Assert */
+ 0, /* Assert not */
+ 0, /* Assert behind */
+ 0, /* Assert behind not */
+ 0, /* ONCE */
+ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */
+ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */
+ 0, 0, /* CREF, DNCREF */
+ 0, 0, /* RREF, DNRREF */
+ 0, 0, /* FALSE, TRUE */
+ 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */
+ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */
+ 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */
+ 0, 0, /* COMMIT, COMMIT_ARG */
+ 0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */
+ 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */
+};
+
+/* This table identifies those opcodes that inspect a character. It is used to
+remember the fact that a character could have been inspected when the end of
+the subject is reached. ***NOTE*** If the start of this table is modified, the
+two tables that follow must also be modified. */
+
+static const uint8_t poptable[] = {
+ 0, /* End */
+ 0, 0, 0, 1, 1, /* \A, \G, \K, \B, \b */
+ 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */
+ 1, 1, 1, /* Any, AllAny, Anybyte */
+ 1, 1, /* \P, \p */
+ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */
+ 1, /* \X */
+ 0, 0, 0, 0, 0, 0, /* \Z, \z, $, $M, ^, ^M */
+ 1, /* Char */
+ 1, /* Chari */
+ 1, /* not */
+ 1, /* noti */
+ /* Positive single-char repeats */
+ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */
+ 1, 1, 1, /* upto, minupto, exact */
+ 1, 1, 1, 1, /* *+, ++, ?+, upto+ */
+ 1, 1, 1, 1, 1, 1, /* *I, *?I, +I, +?I, ?I, ??I */
+ 1, 1, 1, /* upto I, minupto I, exact I */
+ 1, 1, 1, 1, /* *+I, ++I, ?+I, upto+I */
+ /* Negative single-char repeats - only for chars < 256 */
+ 1, 1, 1, 1, 1, 1, /* NOT *, *?, +, +?, ?, ?? */
+ 1, 1, 1, /* NOT upto, minupto, exact */
+ 1, 1, 1, 1, /* NOT *+, ++, ?+, upto+ */
+ 1, 1, 1, 1, 1, 1, /* NOT *I, *?I, +I, +?I, ?I, ??I */
+ 1, 1, 1, /* NOT upto I, minupto I, exact I */
+ 1, 1, 1, 1, /* NOT *+I, ++I, ?+I, upto+I */
+ /* Positive type repeats */
+ 1, 1, 1, 1, 1, 1, /* Type *, *?, +, +?, ?, ?? */
+ 1, 1, 1, /* Type upto, minupto, exact */
+ 1, 1, 1, 1, /* Type *+, ++, ?+, upto+ */
+ /* Character class & ref repeats */
+ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */
+ 1, 1, /* CRRANGE, CRMINRANGE */
+ 1, 1, 1, 1, /* Possessive *+, ++, ?+, CRPOSRANGE */
+ 1, /* CLASS */
+ 1, /* NCLASS */
+ 1, /* XCLASS - variable length */
+ 0, /* REF */
+ 0, /* REFI */
+ 0, /* DNREF */
+ 0, /* DNREFI */
+ 0, /* RECURSE */
+ 0, /* CALLOUT */
+ 0, /* CALLOUT_STR */
+ 0, /* Alt */
+ 0, /* Ket */
+ 0, /* KetRmax */
+ 0, /* KetRmin */
+ 0, /* KetRpos */
+ 0, /* Reverse */
+ 0, /* Assert */
+ 0, /* Assert not */
+ 0, /* Assert behind */
+ 0, /* Assert behind not */
+ 0, /* ONCE */
+ 0, 0, 0, 0, 0, /* BRA, BRAPOS, CBRA, CBRAPOS, COND */
+ 0, 0, 0, 0, 0, /* SBRA, SBRAPOS, SCBRA, SCBRAPOS, SCOND */
+ 0, 0, /* CREF, DNCREF */
+ 0, 0, /* RREF, DNRREF */
+ 0, 0, /* FALSE, TRUE */
+ 0, 0, 0, /* BRAZERO, BRAMINZERO, BRAPOSZERO */
+ 0, 0, 0, /* MARK, PRUNE, PRUNE_ARG */
+ 0, 0, 0, 0, /* SKIP, SKIP_ARG, THEN, THEN_ARG */
+ 0, 0, /* COMMIT, COMMIT_ARG */
+ 0, 0, 0, /* FAIL, ACCEPT, ASSERT_ACCEPT */
+ 0, 0, 0 /* CLOSE, SKIPZERO, DEFINE */
+};
+
+/* These 2 tables allow for compact code for testing for \D, \d, \S, \s, \W,
+and \w */
+
+static const uint8_t toptable1[] = {
+ 0, 0, 0, 0, 0, 0,
+ ctype_digit, ctype_digit,
+ ctype_space, ctype_space,
+ ctype_word, ctype_word,
+ 0, 0 /* OP_ANY, OP_ALLANY */
+};
+
+static const uint8_t toptable2[] = {
+ 0, 0, 0, 0, 0, 0,
+ ctype_digit, 0,
+ ctype_space, 0,
+ ctype_word, 0,
+ 1, 1 /* OP_ANY, OP_ALLANY */
+};
+
+
+/* Structure for holding data about a particular state, which is in effect the
+current data for an active path through the match tree. It must consist
+entirely of ints because the working vector we are passed, and which we put
+these structures in, is a vector of ints. */
+
+typedef struct stateblock {
+ int offset; /* Offset to opcode (-ve has meaning) */
+ int count; /* Count for repeats */
+ int data; /* Some use extra data */
+} stateblock;
+
+#define INTS_PER_STATEBLOCK (int)(sizeof(stateblock)/sizeof(int))
+
+
+/* Before version 10.32 the recursive calls of internal_dfa_match() were passed
+local working space and output vectors that were created on the stack. This has
+caused issues for some patterns, especially in small-stack environments such as
+Windows. A new scheme is now in use which sets up a vector on the stack, but if
+this is too small, heap memory is used, up to the heap_limit. The main
+parameters are all numbers of ints because the workspace is a vector of ints.
+
+The size of the starting stack vector, DFA_START_RWS_SIZE, is in bytes, and is
+defined in pcre2_internal.h so as to be available to pcre2test when it is
+finding the minimum heap requirement for a match. */
+
+#define OVEC_UNIT (sizeof(PCRE2_SIZE)/sizeof(int))
+
+#define RWS_BASE_SIZE (DFA_START_RWS_SIZE/sizeof(int)) /* Stack vector */
+#define RWS_RSIZE 1000 /* Work size for recursion */
+#define RWS_OVEC_RSIZE (1000*OVEC_UNIT) /* Ovector for recursion */
+#define RWS_OVEC_OSIZE (2*OVEC_UNIT) /* Ovector in other cases */
+
+/* This structure is at the start of each workspace block. */
+
+typedef struct RWS_anchor {
+ struct RWS_anchor *next;
+ unsigned int size; /* Number of ints */
+ unsigned int free; /* Number of ints */
+} RWS_anchor;
+
+#define RWS_ANCHOR_SIZE (sizeof(RWS_anchor)/sizeof(int))
+
+
+
+/*************************************************
+* Process a callout *
+*************************************************/
+
+/* This function is called to perform a callout.
+
+Arguments:
+ code current code pointer
+ offsets points to current capture offsets
+ current_subject start of current subject match
+ ptr current position in subject
+ mb the match block
+ extracode extra code offset when called from condition
+ lengthptr where to return the callout length
+
+Returns: the return from the callout
+*/
+
+static int
+do_callout(PCRE2_SPTR code, PCRE2_SIZE *offsets, PCRE2_SPTR current_subject,
+ PCRE2_SPTR ptr, dfa_match_block *mb, PCRE2_SIZE extracode,
+ PCRE2_SIZE *lengthptr)
+{
+pcre2_callout_block *cb = mb->cb;
+
+*lengthptr = (code[extracode] == OP_CALLOUT)?
+ (PCRE2_SIZE)PRIV(OP_lengths)[OP_CALLOUT] :
+ (PCRE2_SIZE)GET(code, 1 + 2*LINK_SIZE + extracode);
+
+if (mb->callout == NULL) return 0; /* No callout provided */
+
+/* Fixed fields in the callout block are set once and for all at the start of
+matching. */
+
+cb->offset_vector = offsets;
+cb->start_match = (PCRE2_SIZE)(current_subject - mb->start_subject);
+cb->current_position = (PCRE2_SIZE)(ptr - mb->start_subject);
+cb->pattern_position = GET(code, 1 + extracode);
+cb->next_item_length = GET(code, 1 + LINK_SIZE + extracode);
+
+if (code[extracode] == OP_CALLOUT)
+ {
+ cb->callout_number = code[1 + 2*LINK_SIZE + extracode];
+ cb->callout_string_offset = 0;
+ cb->callout_string = NULL;
+ cb->callout_string_length = 0;
+ }
+else
+ {
+ cb->callout_number = 0;
+ cb->callout_string_offset = GET(code, 1 + 3*LINK_SIZE + extracode);
+ cb->callout_string = code + (1 + 4*LINK_SIZE + extracode) + 1;
+ cb->callout_string_length = *lengthptr - (1 + 4*LINK_SIZE) - 2;
+ }
+
+return (mb->callout)(cb, mb->callout_data);
+}
+
+
+
+/*************************************************
+* Expand local workspace memory *
+*************************************************/
+
+/* This function is called when internal_dfa_match() is about to be called
+recursively and there is insufficient working space left in the current
+workspace block. If there's an existing next block, use it; otherwise get a new
+block unless the heap limit is reached.
+
+Arguments:
+ rwsptr pointer to block pointer (updated)
+ ovecsize space needed for an ovector
+ mb the match block
+
+Returns: 0 rwsptr has been updated
+ !0 an error code
+*/
+
+static int
+more_workspace(RWS_anchor **rwsptr, unsigned int ovecsize, dfa_match_block *mb)
+{
+RWS_anchor *rws = *rwsptr;
+RWS_anchor *new;
+
+if (rws->next != NULL)
+ {
+ new = rws->next;
+ }
+
+/* All sizes are in units of sizeof(int), except for mb->heaplimit, which is in
+kibibytes. */
+
+else
+ {
+ unsigned int newsize = rws->size * 2;
+ unsigned int heapleft = (unsigned int)
+ (((1024/sizeof(int))*mb->heap_limit - mb->heap_used));
+ if (newsize > heapleft) newsize = heapleft;
+ if (newsize < RWS_RSIZE + ovecsize + RWS_ANCHOR_SIZE)
+ return PCRE2_ERROR_HEAPLIMIT;
+ new = mb->memctl.malloc(newsize*sizeof(int), mb->memctl.memory_data);
+ if (new == NULL) return PCRE2_ERROR_NOMEMORY;
+ mb->heap_used += newsize;
+ new->next = NULL;
+ new->size = newsize;
+ rws->next = new;
+ }
+
+new->free = new->size - RWS_ANCHOR_SIZE;
+*rwsptr = new;
+return 0;
+}
+
+
+
+/*************************************************
+* Match a Regular Expression - DFA engine *
+*************************************************/
+
+/* This internal function applies a compiled pattern to a subject string,
+starting at a given point, using a DFA engine. This function is called from the
+external one, possibly multiple times if the pattern is not anchored. The
+function calls itself recursively for some kinds of subpattern.
+
+Arguments:
+ mb the match_data block with fixed information
+ this_start_code the opening bracket of this subexpression's code
+ current_subject where we currently are in the subject string
+ start_offset start offset in the subject string
+ offsets vector to contain the matching string offsets
+ offsetcount size of same
+ workspace vector of workspace
+ wscount size of same
+ rlevel function call recursion level
+
+Returns: > 0 => number of match offset pairs placed in offsets
+ = 0 => offsets overflowed; longest matches are present
+ -1 => failed to match
+ < -1 => some kind of unexpected problem
+
+The following macros are used for adding states to the two state vectors (one
+for the current character, one for the following character). */
+
+#define ADD_ACTIVE(x,y) \
+ if (active_count++ < wscount) \
+ { \
+ next_active_state->offset = (x); \
+ next_active_state->count = (y); \
+ next_active_state++; \
+ } \
+ else return PCRE2_ERROR_DFA_WSSIZE
+
+#define ADD_ACTIVE_DATA(x,y,z) \
+ if (active_count++ < wscount) \
+ { \
+ next_active_state->offset = (x); \
+ next_active_state->count = (y); \
+ next_active_state->data = (z); \
+ next_active_state++; \
+ } \
+ else return PCRE2_ERROR_DFA_WSSIZE
+
+#define ADD_NEW(x,y) \
+ if (new_count++ < wscount) \
+ { \
+ next_new_state->offset = (x); \
+ next_new_state->count = (y); \
+ next_new_state++; \
+ } \
+ else return PCRE2_ERROR_DFA_WSSIZE
+
+#define ADD_NEW_DATA(x,y,z) \
+ if (new_count++ < wscount) \
+ { \
+ next_new_state->offset = (x); \
+ next_new_state->count = (y); \
+ next_new_state->data = (z); \
+ next_new_state++; \
+ } \
+ else return PCRE2_ERROR_DFA_WSSIZE
+
+/* And now, here is the code */
+
+static int
+internal_dfa_match(
+ dfa_match_block *mb,
+ PCRE2_SPTR this_start_code,
+ PCRE2_SPTR current_subject,
+ PCRE2_SIZE start_offset,
+ PCRE2_SIZE *offsets,
+ uint32_t offsetcount,
+ int *workspace,
+ int wscount,
+ uint32_t rlevel,
+ int *RWS)
+{
+stateblock *active_states, *new_states, *temp_states;
+stateblock *next_active_state, *next_new_state;
+const uint8_t *ctypes, *lcc, *fcc;
+PCRE2_SPTR ptr;
+PCRE2_SPTR end_code;
+dfa_recursion_info new_recursive;
+int active_count, new_count, match_count;
+
+/* Some fields in the mb block are frequently referenced, so we load them into
+independent variables in the hope that this will perform better. */
+
+PCRE2_SPTR start_subject = mb->start_subject;
+PCRE2_SPTR end_subject = mb->end_subject;
+PCRE2_SPTR start_code = mb->start_code;
+
+#ifdef SUPPORT_UNICODE
+BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
+#else
+BOOL utf = FALSE;
+#endif
+
+BOOL reset_could_continue = FALSE;
+
+if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT;
+if (rlevel++ > mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT;
+offsetcount &= (uint32_t)(-2); /* Round down */
+
+wscount -= 2;
+wscount = (wscount - (wscount % (INTS_PER_STATEBLOCK * 2))) /
+ (2 * INTS_PER_STATEBLOCK);
+
+ctypes = mb->tables + ctypes_offset;
+lcc = mb->tables + lcc_offset;
+fcc = mb->tables + fcc_offset;
+
+match_count = PCRE2_ERROR_NOMATCH; /* A negative number */
+
+active_states = (stateblock *)(workspace + 2);
+next_new_state = new_states = active_states + wscount;
+new_count = 0;
+
+/* The first thing in any (sub) pattern is a bracket of some sort. Push all
+the alternative states onto the list, and find out where the end is. This
+makes is possible to use this function recursively, when we want to stop at a
+matching internal ket rather than at the end.
+
+If we are dealing with a backward assertion we have to find out the maximum
+amount to move back, and set up each alternative appropriately. */
+
+if (*this_start_code == OP_ASSERTBACK || *this_start_code == OP_ASSERTBACK_NOT)
+ {
+ size_t max_back = 0;
+ size_t gone_back;
+
+ end_code = this_start_code;
+ do
+ {
+ size_t back = (size_t)GET(end_code, 2+LINK_SIZE);
+ if (back > max_back) max_back = back;
+ end_code += GET(end_code, 1);
+ }
+ while (*end_code == OP_ALT);
+
+ /* If we can't go back the amount required for the longest lookbehind
+ pattern, go back as far as we can; some alternatives may still be viable. */
+
+#ifdef SUPPORT_UNICODE
+ /* In character mode we have to step back character by character */
+
+ if (utf)
+ {
+ for (gone_back = 0; gone_back < max_back; gone_back++)
+ {
+ if (current_subject <= start_subject) break;
+ current_subject--;
+ ACROSSCHAR(current_subject > start_subject, current_subject,
+ current_subject--);
+ }
+ }
+ else
+#endif
+
+ /* In byte-mode we can do this quickly. */
+
+ {
+ size_t current_offset = (size_t)(current_subject - start_subject);
+ gone_back = (current_offset < max_back)? current_offset : max_back;
+ current_subject -= gone_back;
+ }
+
+ /* Save the earliest consulted character */
+
+ if (current_subject < mb->start_used_ptr)
+ mb->start_used_ptr = current_subject;
+
+ /* Now we can process the individual branches. There will be an OP_REVERSE at
+ the start of each branch, except when the length of the branch is zero. */
+
+ end_code = this_start_code;
+ do
+ {
+ uint32_t revlen = (end_code[1+LINK_SIZE] == OP_REVERSE)? 1 + LINK_SIZE : 0;
+ size_t back = (revlen == 0)? 0 : (size_t)GET(end_code, 2+LINK_SIZE);
+ if (back <= gone_back)
+ {
+ int bstate = (int)(end_code - start_code + 1 + LINK_SIZE + revlen);
+ ADD_NEW_DATA(-bstate, 0, (int)(gone_back - back));
+ }
+ end_code += GET(end_code, 1);
+ }
+ while (*end_code == OP_ALT);
+ }
+
+/* This is the code for a "normal" subpattern (not a backward assertion). The
+start of a whole pattern is always one of these. If we are at the top level,
+we may be asked to restart matching from the same point that we reached for a
+previous partial match. We still have to scan through the top-level branches to
+find the end state. */
+
+else
+ {
+ end_code = this_start_code;
+
+ /* Restarting */
+
+ if (rlevel == 1 && (mb->moptions & PCRE2_DFA_RESTART) != 0)
+ {
+ do { end_code += GET(end_code, 1); } while (*end_code == OP_ALT);
+ new_count = workspace[1];
+ if (!workspace[0])
+ memcpy(new_states, active_states, (size_t)new_count * sizeof(stateblock));
+ }
+
+ /* Not restarting */
+
+ else
+ {
+ int length = 1 + LINK_SIZE +
+ ((*this_start_code == OP_CBRA || *this_start_code == OP_SCBRA ||
+ *this_start_code == OP_CBRAPOS || *this_start_code == OP_SCBRAPOS)
+ ? IMM2_SIZE:0);
+ do
+ {
+ ADD_NEW((int)(end_code - start_code + length), 0);
+ end_code += GET(end_code, 1);
+ length = 1 + LINK_SIZE;
+ }
+ while (*end_code == OP_ALT);
+ }
+ }
+
+workspace[0] = 0; /* Bit indicating which vector is current */
+
+/* Loop for scanning the subject */
+
+ptr = current_subject;
+for (;;)
+ {
+ int i, j;
+ int clen, dlen;
+ uint32_t c, d;
+ int forced_fail = 0;
+ BOOL partial_newline = FALSE;
+ BOOL could_continue = reset_could_continue;
+ reset_could_continue = FALSE;
+
+ if (ptr > mb->last_used_ptr) mb->last_used_ptr = ptr;
+
+ /* Make the new state list into the active state list and empty the
+ new state list. */
+
+ temp_states = active_states;
+ active_states = new_states;
+ new_states = temp_states;
+ active_count = new_count;
+ new_count = 0;
+
+ workspace[0] ^= 1; /* Remember for the restarting feature */
+ workspace[1] = active_count;
+
+ /* Set the pointers for adding new states */
+
+ next_active_state = active_states + active_count;
+ next_new_state = new_states;
+
+ /* Load the current character from the subject outside the loop, as many
+ different states may want to look at it, and we assume that at least one
+ will. */
+
+ if (ptr < end_subject)
+ {
+ clen = 1; /* Number of data items in the character */
+#ifdef SUPPORT_UNICODE
+ GETCHARLENTEST(c, ptr, clen);
+#else
+ c = *ptr;
+#endif /* SUPPORT_UNICODE */
+ }
+ else
+ {
+ clen = 0; /* This indicates the end of the subject */
+ c = NOTACHAR; /* This value should never actually be used */
+ }
+
+ /* Scan up the active states and act on each one. The result of an action
+ may be to add more states to the currently active list (e.g. on hitting a
+ parenthesis) or it may be to put states on the new list, for considering
+ when we move the character pointer on. */
+
+ for (i = 0; i < active_count; i++)
+ {
+ stateblock *current_state = active_states + i;
+ BOOL caseless = FALSE;
+ PCRE2_SPTR code;
+ uint32_t codevalue;
+ int state_offset = current_state->offset;
+ int rrc;
+ int count;
+
+ /* A negative offset is a special case meaning "hold off going to this
+ (negated) state until the number of characters in the data field have
+ been skipped". If the could_continue flag was passed over from a previous
+ state, arrange for it to passed on. */
+
+ if (state_offset < 0)
+ {
+ if (current_state->data > 0)
+ {
+ ADD_NEW_DATA(state_offset, current_state->count,
+ current_state->data - 1);
+ if (could_continue) reset_could_continue = TRUE;
+ continue;
+ }
+ else
+ {
+ current_state->offset = state_offset = -state_offset;
+ }
+ }
+
+ /* Check for a duplicate state with the same count, and skip if found.
+ See the note at the head of this module about the possibility of improving
+ performance here. */
+
+ for (j = 0; j < i; j++)
+ {
+ if (active_states[j].offset == state_offset &&
+ active_states[j].count == current_state->count)
+ goto NEXT_ACTIVE_STATE;
+ }
+
+ /* The state offset is the offset to the opcode */
+
+ code = start_code + state_offset;
+ codevalue = *code;
+
+ /* If this opcode inspects a character, but we are at the end of the
+ subject, remember the fact for use when testing for a partial match. */
+
+ if (clen == 0 && poptable[codevalue] != 0)
+ could_continue = TRUE;
+
+ /* If this opcode is followed by an inline character, load it. It is
+ tempting to test for the presence of a subject character here, but that
+ is wrong, because sometimes zero repetitions of the subject are
+ permitted.
+
+ We also use this mechanism for opcodes such as OP_TYPEPLUS that take an
+ argument that is not a data character - but is always one byte long because
+ the values are small. We have to take special action to deal with \P, \p,
+ \H, \h, \V, \v and \X in this case. To keep the other cases fast, convert
+ these ones to new opcodes. */
+
+ if (coptable[codevalue] > 0)
+ {
+ dlen = 1;
+#ifdef SUPPORT_UNICODE
+ if (utf) { GETCHARLEN(d, (code + coptable[codevalue]), dlen); } else
+#endif /* SUPPORT_UNICODE */
+ d = code[coptable[codevalue]];
+ if (codevalue >= OP_TYPESTAR)
+ {
+ switch(d)
+ {
+ case OP_ANYBYTE: return PCRE2_ERROR_DFA_UITEM;
+ case OP_NOTPROP:
+ case OP_PROP: codevalue += OP_PROP_EXTRA; break;
+ case OP_ANYNL: codevalue += OP_ANYNL_EXTRA; break;
+ case OP_EXTUNI: codevalue += OP_EXTUNI_EXTRA; break;
+ case OP_NOT_HSPACE:
+ case OP_HSPACE: codevalue += OP_HSPACE_EXTRA; break;
+ case OP_NOT_VSPACE:
+ case OP_VSPACE: codevalue += OP_VSPACE_EXTRA; break;
+ default: break;
+ }
+ }
+ }
+ else
+ {
+ dlen = 0; /* Not strictly necessary, but compilers moan */
+ d = NOTACHAR; /* if these variables are not set. */
+ }
+
+
+ /* Now process the individual opcodes */
+
+ switch (codevalue)
+ {
+/* ========================================================================== */
+ /* These cases are never obeyed. This is a fudge that causes a compile-
+ time error if the vectors coptable or poptable, which are indexed by
+ opcode, are not the correct length. It seems to be the only way to do
+ such a check at compile time, as the sizeof() operator does not work
+ in the C preprocessor. */
+
+ case OP_TABLE_LENGTH:
+ case OP_TABLE_LENGTH +
+ ((sizeof(coptable) == OP_TABLE_LENGTH) &&
+ (sizeof(poptable) == OP_TABLE_LENGTH)):
+ return 0;
+
+/* ========================================================================== */
+ /* Reached a closing bracket. If not at the end of the pattern, carry
+ on with the next opcode. For repeating opcodes, also add the repeat
+ state. Note that KETRPOS will always be encountered at the end of the
+ subpattern, because the possessive subpattern repeats are always handled
+ using recursive calls. Thus, it never adds any new states.
+
+ At the end of the (sub)pattern, unless we have an empty string and
+ PCRE2_NOTEMPTY is set, or PCRE2_NOTEMPTY_ATSTART is set and we are at the
+ start of the subject, save the match data, shifting up all previous
+ matches so we always have the longest first. */
+
+ case OP_KET:
+ case OP_KETRMIN:
+ case OP_KETRMAX:
+ case OP_KETRPOS:
+ if (code != end_code)
+ {
+ ADD_ACTIVE(state_offset + 1 + LINK_SIZE, 0);
+ if (codevalue != OP_KET)
+ {
+ ADD_ACTIVE(state_offset - (int)GET(code, 1), 0);
+ }
+ }
+ else
+ {
+ if (ptr > current_subject ||
+ ((mb->moptions & PCRE2_NOTEMPTY) == 0 &&
+ ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) == 0 ||
+ current_subject > start_subject + mb->start_offset)))
+ {
+ if (match_count < 0) match_count = (offsetcount >= 2)? 1 : 0;
+ else if (match_count > 0 && ++match_count * 2 > (int)offsetcount)
+ match_count = 0;
+ count = ((match_count == 0)? (int)offsetcount : match_count * 2) - 2;
+ if (count > 0) (void)memmove(offsets + 2, offsets,
+ (size_t)count * sizeof(PCRE2_SIZE));
+ if (offsetcount >= 2)
+ {
+ offsets[0] = (PCRE2_SIZE)(current_subject - start_subject);
+ offsets[1] = (PCRE2_SIZE)(ptr - start_subject);
+ }
+ if ((mb->moptions & PCRE2_DFA_SHORTEST) != 0) return match_count;
+ }
+ }
+ break;
+
+/* ========================================================================== */
+ /* These opcodes add to the current list of states without looking
+ at the current character. */
+
+ /*-----------------------------------------------------------------*/
+ case OP_ALT:
+ do { code += GET(code, 1); } while (*code == OP_ALT);
+ ADD_ACTIVE((int)(code - start_code), 0);
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_BRA:
+ case OP_SBRA:
+ do
+ {
+ ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+ code += GET(code, 1);
+ }
+ while (*code == OP_ALT);
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_CBRA:
+ case OP_SCBRA:
+ ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE + IMM2_SIZE), 0);
+ code += GET(code, 1);
+ while (*code == OP_ALT)
+ {
+ ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+ code += GET(code, 1);
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ ADD_ACTIVE(state_offset + 1, 0);
+ code += 1 + GET(code, 2);
+ while (*code == OP_ALT) code += GET(code, 1);
+ ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_SKIPZERO:
+ code += 1 + GET(code, 2);
+ while (*code == OP_ALT) code += GET(code, 1);
+ ADD_ACTIVE((int)(code - start_code + 1 + LINK_SIZE), 0);
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_CIRC:
+ if (ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0)
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_CIRCM:
+ if ((ptr == start_subject && (mb->moptions & PCRE2_NOTBOL) == 0) ||
+ ((ptr != end_subject || (mb->poptions & PCRE2_ALT_CIRCUMFLEX) != 0 )
+ && WAS_NEWLINE(ptr)))
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_EOD:
+ if (ptr >= end_subject)
+ {
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ could_continue = TRUE;
+ else { ADD_ACTIVE(state_offset + 1, 0); }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_SOD:
+ if (ptr == start_subject) { ADD_ACTIVE(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_SOM:
+ if (ptr == start_subject + start_offset) { ADD_ACTIVE(state_offset + 1, 0); }
+ break;
+
+
+/* ========================================================================== */
+ /* These opcodes inspect the next subject character, and sometimes
+ the previous one as well, but do not have an argument. The variable
+ clen contains the length of the current character and is zero if we are
+ at the end of the subject. */
+
+ /*-----------------------------------------------------------------*/
+ case OP_ANY:
+ if (clen > 0 && !IS_NEWLINE(ptr))
+ {
+ if (ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ could_continue = partial_newline = TRUE;
+ }
+ else
+ {
+ ADD_NEW(state_offset + 1, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_ALLANY:
+ if (clen > 0)
+ { ADD_NEW(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_EODN:
+ if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ could_continue = TRUE;
+ else if (clen == 0 || (IS_NEWLINE(ptr) && ptr == end_subject - mb->nllen))
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_DOLL:
+ if ((mb->moptions & PCRE2_NOTEOL) == 0)
+ {
+ if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ could_continue = TRUE;
+ else if (clen == 0 ||
+ ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr) &&
+ (ptr == end_subject - mb->nllen)
+ ))
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ else if (ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ {
+ reset_could_continue = TRUE;
+ ADD_NEW_DATA(-(state_offset + 1), 0, 1);
+ }
+ else could_continue = partial_newline = TRUE;
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_DOLLM:
+ if ((mb->moptions & PCRE2_NOTEOL) == 0)
+ {
+ if (clen == 0 && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ could_continue = TRUE;
+ else if (clen == 0 ||
+ ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0 && IS_NEWLINE(ptr)))
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ else if (ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ {
+ reset_could_continue = TRUE;
+ ADD_NEW_DATA(-(state_offset + 1), 0, 1);
+ }
+ else could_continue = partial_newline = TRUE;
+ }
+ }
+ else if (IS_NEWLINE(ptr))
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+
+ case OP_DIGIT:
+ case OP_WHITESPACE:
+ case OP_WORDCHAR:
+ if (clen > 0 && c < 256 &&
+ ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0)
+ { ADD_NEW(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_NOT_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ if (clen > 0 && (c >= 256 ||
+ ((ctypes[c] & toptable1[codevalue]) ^ toptable2[codevalue]) != 0))
+ { ADD_NEW(state_offset + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ {
+ int left_word, right_word;
+
+ if (ptr > start_subject)
+ {
+ PCRE2_SPTR temp = ptr - 1;
+ if (temp < mb->start_used_ptr) mb->start_used_ptr = temp;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf) { BACKCHAR(temp); }
+#endif
+ GETCHARTEST(d, temp);
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
+ {
+ if (d == '_') left_word = TRUE; else
+ {
+ uint32_t cat = UCD_CATEGORY(d);
+ left_word = (cat == ucp_L || cat == ucp_N);
+ }
+ }
+ else
+#endif
+ left_word = d < 256 && (ctypes[d] & ctype_word) != 0;
+ }
+ else left_word = FALSE;
+
+ if (clen > 0)
+ {
+ if (ptr >= mb->last_used_ptr)
+ {
+ PCRE2_SPTR temp = ptr + 1;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf) { FORWARDCHARTEST(temp, mb->end_subject); }
+#endif
+ mb->last_used_ptr = temp;
+ }
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
+ {
+ if (c == '_') right_word = TRUE; else
+ {
+ uint32_t cat = UCD_CATEGORY(c);
+ right_word = (cat == ucp_L || cat == ucp_N);
+ }
+ }
+ else
+#endif
+ right_word = c < 256 && (ctypes[c] & ctype_word) != 0;
+ }
+ else right_word = FALSE;
+
+ if ((left_word == right_word) == (codevalue == OP_NOT_WORD_BOUNDARY))
+ { ADD_ACTIVE(state_offset + 1, 0); }
+ }
+ break;
+
+
+ /*-----------------------------------------------------------------*/
+ /* Check the next character by Unicode property. We will get here only
+ if the support is in the binary; otherwise a compile-time error occurs.
+ */
+
+#ifdef SUPPORT_UNICODE
+ case OP_PROP:
+ case OP_NOTPROP:
+ if (clen > 0)
+ {
+ BOOL OK;
+ const uint32_t *cp;
+ const ucd_record * prop = GET_UCD(c);
+ switch(code[1])
+ {
+ case PT_ANY:
+ OK = TRUE;
+ break;
+
+ case PT_LAMP:
+ OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt;
+ break;
+
+ case PT_GC:
+ OK = PRIV(ucp_gentype)[prop->chartype] == code[2];
+ break;
+
+ case PT_PC:
+ OK = prop->chartype == code[2];
+ break;
+
+ case PT_SC:
+ OK = prop->script == code[2];
+ break;
+
+ /* These are specials for combination cases. */
+
+ case PT_ALNUM:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+ break;
+ }
+ break;
+
+ case PT_WORD:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ c == CHAR_UNDERSCORE;
+ break;
+
+ case PT_CLIST:
+ cp = PRIV(ucd_caseless_sets) + code[2];
+ for (;;)
+ {
+ if (c < *cp) { OK = FALSE; break; }
+ if (c == *cp++) { OK = TRUE; break; }
+ }
+ break;
+
+ case PT_UCNC:
+ OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+ c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+ c >= 0xe000;
+ break;
+
+ /* Should never occur, but keep compilers from grumbling. */
+
+ default:
+ OK = codevalue != OP_PROP;
+ break;
+ }
+
+ if (OK == (codevalue == OP_PROP)) { ADD_NEW(state_offset + 3, 0); }
+ }
+ break;
+#endif
+
+
+
+/* ========================================================================== */
+ /* These opcodes likewise inspect the subject character, but have an
+ argument that is not a data character. It is one of these opcodes:
+ OP_ANY, OP_ALLANY, OP_DIGIT, OP_NOT_DIGIT, OP_WHITESPACE, OP_NOT_SPACE,
+ OP_WORDCHAR, OP_NOT_WORDCHAR. The value is loaded into d. */
+
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+ if (clen > 0)
+ {
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ could_continue = partial_newline = TRUE;
+ }
+ else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+ (c < 256 &&
+ (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+ ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+ {
+ if (count > 0 && codevalue == OP_TYPEPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW(state_offset, count);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSQUERY:
+ ADD_ACTIVE(state_offset + 2, 0);
+ if (clen > 0)
+ {
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ could_continue = partial_newline = TRUE;
+ }
+ else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+ (c < 256 &&
+ (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+ ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+ {
+ if (codevalue == OP_TYPEPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(state_offset + 2, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPOSSTAR:
+ ADD_ACTIVE(state_offset + 2, 0);
+ if (clen > 0)
+ {
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ could_continue = partial_newline = TRUE;
+ }
+ else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+ (c < 256 &&
+ (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+ ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+ {
+ if (codevalue == OP_TYPEPOSSTAR)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(state_offset, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_TYPEEXACT:
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ could_continue = partial_newline = TRUE;
+ }
+ else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+ (c < 256 &&
+ (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+ ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+ {
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW(state_offset + 1 + IMM2_SIZE + 1, 0); }
+ else
+ { ADD_NEW(state_offset, count); }
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0);
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ if (d == OP_ANY && ptr + 1 >= mb->end_subject &&
+ (mb->moptions & (PCRE2_PARTIAL_HARD)) != 0 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ c == NLBLOCK->nl[0])
+ {
+ could_continue = partial_newline = TRUE;
+ }
+ else if ((c >= 256 && d != OP_DIGIT && d != OP_WHITESPACE && d != OP_WORDCHAR) ||
+ (c < 256 &&
+ (d != OP_ANY || !IS_NEWLINE(ptr)) &&
+ ((ctypes[c] & toptable1[d]) ^ toptable2[d]) != 0))
+ {
+ if (codevalue == OP_TYPEPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW(state_offset + 2 + IMM2_SIZE, 0); }
+ else
+ { ADD_NEW(state_offset, count); }
+ }
+ }
+ break;
+
+/* ========================================================================== */
+ /* These are virtual opcodes that are used when something like
+ OP_TYPEPLUS has OP_PROP, OP_NOTPROP, OP_ANYNL, or OP_EXTUNI as its
+ argument. It keeps the code above fast for the other cases. The argument
+ is in the d variable. */
+
+#ifdef SUPPORT_UNICODE
+ case OP_PROP_EXTRA + OP_TYPEPLUS:
+ case OP_PROP_EXTRA + OP_TYPEMINPLUS:
+ case OP_PROP_EXTRA + OP_TYPEPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + 4, 0); }
+ if (clen > 0)
+ {
+ BOOL OK;
+ const uint32_t *cp;
+ const ucd_record * prop = GET_UCD(c);
+ switch(code[2])
+ {
+ case PT_ANY:
+ OK = TRUE;
+ break;
+
+ case PT_LAMP:
+ OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt;
+ break;
+
+ case PT_GC:
+ OK = PRIV(ucp_gentype)[prop->chartype] == code[3];
+ break;
+
+ case PT_PC:
+ OK = prop->chartype == code[3];
+ break;
+
+ case PT_SC:
+ OK = prop->script == code[3];
+ break;
+
+ /* These are specials for combination cases. */
+
+ case PT_ALNUM:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+ break;
+ }
+ break;
+
+ case PT_WORD:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ c == CHAR_UNDERSCORE;
+ break;
+
+ case PT_CLIST:
+ cp = PRIV(ucd_caseless_sets) + code[3];
+ for (;;)
+ {
+ if (c < *cp) { OK = FALSE; break; }
+ if (c == *cp++) { OK = TRUE; break; }
+ }
+ break;
+
+ case PT_UCNC:
+ OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+ c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+ c >= 0xe000;
+ break;
+
+ /* Should never occur, but keep compilers from grumbling. */
+
+ default:
+ OK = codevalue != OP_PROP;
+ break;
+ }
+
+ if (OK == (d == OP_PROP))
+ {
+ if (count > 0 && codevalue == OP_PROP_EXTRA + OP_TYPEPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW(state_offset, count);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_EXTUNI_EXTRA + OP_TYPEPLUS:
+ case OP_EXTUNI_EXTRA + OP_TYPEMINPLUS:
+ case OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+ if (clen > 0)
+ {
+ int ncount = 0;
+ if (count > 0 && codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf,
+ &ncount);
+ count++;
+ ADD_NEW_DATA(-state_offset, count, ncount);
+ }
+ break;
+#endif
+
+ /*-----------------------------------------------------------------*/
+ case OP_ANYNL_EXTRA + OP_TYPEPLUS:
+ case OP_ANYNL_EXTRA + OP_TYPEMINPLUS:
+ case OP_ANYNL_EXTRA + OP_TYPEPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+ if (clen > 0)
+ {
+ int ncount = 0;
+ switch (c)
+ {
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+ goto ANYNL01;
+
+ case CHAR_CR:
+ if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1;
+ /* Fall through */
+
+ ANYNL01:
+ case CHAR_LF:
+ if (count > 0 && codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW_DATA(-state_offset, count, ncount);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_VSPACE_EXTRA + OP_TYPEPLUS:
+ case OP_VSPACE_EXTRA + OP_TYPEMINPLUS:
+ case OP_VSPACE_EXTRA + OP_TYPEPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+ if (clen > 0)
+ {
+ BOOL OK;
+ switch (c)
+ {
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = FALSE;
+ break;
+ }
+
+ if (OK == (d == OP_VSPACE))
+ {
+ if (count > 0 && codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW_DATA(-state_offset, count, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_HSPACE_EXTRA + OP_TYPEPLUS:
+ case OP_HSPACE_EXTRA + OP_TYPEMINPLUS:
+ case OP_HSPACE_EXTRA + OP_TYPEPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + 2, 0); }
+ if (clen > 0)
+ {
+ BOOL OK;
+ switch (c)
+ {
+ HSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = FALSE;
+ break;
+ }
+
+ if (OK == (d == OP_HSPACE))
+ {
+ if (count > 0 && codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW_DATA(-state_offset, count, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+#ifdef SUPPORT_UNICODE
+ case OP_PROP_EXTRA + OP_TYPEQUERY:
+ case OP_PROP_EXTRA + OP_TYPEMINQUERY:
+ case OP_PROP_EXTRA + OP_TYPEPOSQUERY:
+ count = 4;
+ goto QS1;
+
+ case OP_PROP_EXTRA + OP_TYPESTAR:
+ case OP_PROP_EXTRA + OP_TYPEMINSTAR:
+ case OP_PROP_EXTRA + OP_TYPEPOSSTAR:
+ count = 0;
+
+ QS1:
+
+ ADD_ACTIVE(state_offset + 4, 0);
+ if (clen > 0)
+ {
+ BOOL OK;
+ const uint32_t *cp;
+ const ucd_record * prop = GET_UCD(c);
+ switch(code[2])
+ {
+ case PT_ANY:
+ OK = TRUE;
+ break;
+
+ case PT_LAMP:
+ OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt;
+ break;
+
+ case PT_GC:
+ OK = PRIV(ucp_gentype)[prop->chartype] == code[3];
+ break;
+
+ case PT_PC:
+ OK = prop->chartype == code[3];
+ break;
+
+ case PT_SC:
+ OK = prop->script == code[3];
+ break;
+
+ /* These are specials for combination cases. */
+
+ case PT_ALNUM:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+ break;
+ }
+ break;
+
+ case PT_WORD:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ c == CHAR_UNDERSCORE;
+ break;
+
+ case PT_CLIST:
+ cp = PRIV(ucd_caseless_sets) + code[3];
+ for (;;)
+ {
+ if (c < *cp) { OK = FALSE; break; }
+ if (c == *cp++) { OK = TRUE; break; }
+ }
+ break;
+
+ case PT_UCNC:
+ OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+ c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+ c >= 0xe000;
+ break;
+
+ /* Should never occur, but keep compilers from grumbling. */
+
+ default:
+ OK = codevalue != OP_PROP;
+ break;
+ }
+
+ if (OK == (d == OP_PROP))
+ {
+ if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSSTAR ||
+ codevalue == OP_PROP_EXTRA + OP_TYPEPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(state_offset + count, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_EXTUNI_EXTRA + OP_TYPEQUERY:
+ case OP_EXTUNI_EXTRA + OP_TYPEMINQUERY:
+ case OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY:
+ count = 2;
+ goto QS2;
+
+ case OP_EXTUNI_EXTRA + OP_TYPESTAR:
+ case OP_EXTUNI_EXTRA + OP_TYPEMINSTAR:
+ case OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR:
+ count = 0;
+
+ QS2:
+
+ ADD_ACTIVE(state_offset + 2, 0);
+ if (clen > 0)
+ {
+ int ncount = 0;
+ if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSSTAR ||
+ codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ (void)PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf,
+ &ncount);
+ ADD_NEW_DATA(-(state_offset + count), 0, ncount);
+ }
+ break;
+#endif
+
+ /*-----------------------------------------------------------------*/
+ case OP_ANYNL_EXTRA + OP_TYPEQUERY:
+ case OP_ANYNL_EXTRA + OP_TYPEMINQUERY:
+ case OP_ANYNL_EXTRA + OP_TYPEPOSQUERY:
+ count = 2;
+ goto QS3;
+
+ case OP_ANYNL_EXTRA + OP_TYPESTAR:
+ case OP_ANYNL_EXTRA + OP_TYPEMINSTAR:
+ case OP_ANYNL_EXTRA + OP_TYPEPOSSTAR:
+ count = 0;
+
+ QS3:
+ ADD_ACTIVE(state_offset + 2, 0);
+ if (clen > 0)
+ {
+ int ncount = 0;
+ switch (c)
+ {
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+ goto ANYNL02;
+
+ case CHAR_CR:
+ if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1;
+ /* Fall through */
+
+ ANYNL02:
+ case CHAR_LF:
+ if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSSTAR ||
+ codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW_DATA(-(state_offset + (int)count), 0, ncount);
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_VSPACE_EXTRA + OP_TYPEQUERY:
+ case OP_VSPACE_EXTRA + OP_TYPEMINQUERY:
+ case OP_VSPACE_EXTRA + OP_TYPEPOSQUERY:
+ count = 2;
+ goto QS4;
+
+ case OP_VSPACE_EXTRA + OP_TYPESTAR:
+ case OP_VSPACE_EXTRA + OP_TYPEMINSTAR:
+ case OP_VSPACE_EXTRA + OP_TYPEPOSSTAR:
+ count = 0;
+
+ QS4:
+ ADD_ACTIVE(state_offset + 2, 0);
+ if (clen > 0)
+ {
+ BOOL OK;
+ switch (c)
+ {
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = FALSE;
+ break;
+ }
+ if (OK == (d == OP_VSPACE))
+ {
+ if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSSTAR ||
+ codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW_DATA(-(state_offset + (int)count), 0, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_HSPACE_EXTRA + OP_TYPEQUERY:
+ case OP_HSPACE_EXTRA + OP_TYPEMINQUERY:
+ case OP_HSPACE_EXTRA + OP_TYPEPOSQUERY:
+ count = 2;
+ goto QS5;
+
+ case OP_HSPACE_EXTRA + OP_TYPESTAR:
+ case OP_HSPACE_EXTRA + OP_TYPEMINSTAR:
+ case OP_HSPACE_EXTRA + OP_TYPEPOSSTAR:
+ count = 0;
+
+ QS5:
+ ADD_ACTIVE(state_offset + 2, 0);
+ if (clen > 0)
+ {
+ BOOL OK;
+ switch (c)
+ {
+ HSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = FALSE;
+ break;
+ }
+
+ if (OK == (d == OP_HSPACE))
+ {
+ if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSSTAR ||
+ codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW_DATA(-(state_offset + (int)count), 0, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+#ifdef SUPPORT_UNICODE
+ case OP_PROP_EXTRA + OP_TYPEEXACT:
+ case OP_PROP_EXTRA + OP_TYPEUPTO:
+ case OP_PROP_EXTRA + OP_TYPEMINUPTO:
+ case OP_PROP_EXTRA + OP_TYPEPOSUPTO:
+ if (codevalue != OP_PROP_EXTRA + OP_TYPEEXACT)
+ { ADD_ACTIVE(state_offset + 1 + IMM2_SIZE + 3, 0); }
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ BOOL OK;
+ const uint32_t *cp;
+ const ucd_record * prop = GET_UCD(c);
+ switch(code[1 + IMM2_SIZE + 1])
+ {
+ case PT_ANY:
+ OK = TRUE;
+ break;
+
+ case PT_LAMP:
+ OK = prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt;
+ break;
+
+ case PT_GC:
+ OK = PRIV(ucp_gentype)[prop->chartype] == code[1 + IMM2_SIZE + 2];
+ break;
+
+ case PT_PC:
+ OK = prop->chartype == code[1 + IMM2_SIZE + 2];
+ break;
+
+ case PT_SC:
+ OK = prop->script == code[1 + IMM2_SIZE + 2];
+ break;
+
+ /* These are specials for combination cases. */
+
+ case PT_ALNUM:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N;
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_Z;
+ break;
+ }
+ break;
+
+ case PT_WORD:
+ OK = PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ c == CHAR_UNDERSCORE;
+ break;
+
+ case PT_CLIST:
+ cp = PRIV(ucd_caseless_sets) + code[1 + IMM2_SIZE + 2];
+ for (;;)
+ {
+ if (c < *cp) { OK = FALSE; break; }
+ if (c == *cp++) { OK = TRUE; break; }
+ }
+ break;
+
+ case PT_UCNC:
+ OK = c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+ c == CHAR_GRAVE_ACCENT || (c >= 0xa0 && c <= 0xd7ff) ||
+ c >= 0xe000;
+ break;
+
+ /* Should never occur, but keep compilers from grumbling. */
+
+ default:
+ OK = codevalue != OP_PROP;
+ break;
+ }
+
+ if (OK == (d == OP_PROP))
+ {
+ if (codevalue == OP_PROP_EXTRA + OP_TYPEPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW(state_offset + 1 + IMM2_SIZE + 3, 0); }
+ else
+ { ADD_NEW(state_offset, count); }
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_EXTUNI_EXTRA + OP_TYPEEXACT:
+ case OP_EXTUNI_EXTRA + OP_TYPEUPTO:
+ case OP_EXTUNI_EXTRA + OP_TYPEMINUPTO:
+ case OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO:
+ if (codevalue != OP_EXTUNI_EXTRA + OP_TYPEEXACT)
+ { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ PCRE2_SPTR nptr;
+ int ncount = 0;
+ if (codevalue == OP_EXTUNI_EXTRA + OP_TYPEPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject, end_subject, utf,
+ &ncount);
+ if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ reset_could_continue = TRUE;
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); }
+ else
+ { ADD_NEW_DATA(-state_offset, count, ncount); }
+ }
+ break;
+#endif
+
+ /*-----------------------------------------------------------------*/
+ case OP_ANYNL_EXTRA + OP_TYPEEXACT:
+ case OP_ANYNL_EXTRA + OP_TYPEUPTO:
+ case OP_ANYNL_EXTRA + OP_TYPEMINUPTO:
+ case OP_ANYNL_EXTRA + OP_TYPEPOSUPTO:
+ if (codevalue != OP_ANYNL_EXTRA + OP_TYPEEXACT)
+ { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ int ncount = 0;
+ switch (c)
+ {
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+ goto ANYNL03;
+
+ case CHAR_CR:
+ if (ptr + 1 < end_subject && UCHAR21TEST(ptr + 1) == CHAR_LF) ncount = 1;
+ /* Fall through */
+
+ ANYNL03:
+ case CHAR_LF:
+ if (codevalue == OP_ANYNL_EXTRA + OP_TYPEPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, ncount); }
+ else
+ { ADD_NEW_DATA(-state_offset, count, ncount); }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_VSPACE_EXTRA + OP_TYPEEXACT:
+ case OP_VSPACE_EXTRA + OP_TYPEUPTO:
+ case OP_VSPACE_EXTRA + OP_TYPEMINUPTO:
+ case OP_VSPACE_EXTRA + OP_TYPEPOSUPTO:
+ if (codevalue != OP_VSPACE_EXTRA + OP_TYPEEXACT)
+ { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ BOOL OK;
+ switch (c)
+ {
+ VSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = FALSE;
+ }
+
+ if (OK == (d == OP_VSPACE))
+ {
+ if (codevalue == OP_VSPACE_EXTRA + OP_TYPEPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); }
+ else
+ { ADD_NEW_DATA(-state_offset, count, 0); }
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_HSPACE_EXTRA + OP_TYPEEXACT:
+ case OP_HSPACE_EXTRA + OP_TYPEUPTO:
+ case OP_HSPACE_EXTRA + OP_TYPEMINUPTO:
+ case OP_HSPACE_EXTRA + OP_TYPEPOSUPTO:
+ if (codevalue != OP_HSPACE_EXTRA + OP_TYPEEXACT)
+ { ADD_ACTIVE(state_offset + 2 + IMM2_SIZE, 0); }
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ BOOL OK;
+ switch (c)
+ {
+ HSPACE_CASES:
+ OK = TRUE;
+ break;
+
+ default:
+ OK = FALSE;
+ break;
+ }
+
+ if (OK == (d == OP_HSPACE))
+ {
+ if (codevalue == OP_HSPACE_EXTRA + OP_TYPEPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW_DATA(-(state_offset + 2 + IMM2_SIZE), 0, 0); }
+ else
+ { ADD_NEW_DATA(-state_offset, count, 0); }
+ }
+ }
+ break;
+
+/* ========================================================================== */
+ /* These opcodes are followed by a character that is usually compared
+ to the current subject character; it is loaded into d. We still get
+ here even if there is no subject character, because in some cases zero
+ repetitions are permitted. */
+
+ /*-----------------------------------------------------------------*/
+ case OP_CHAR:
+ if (clen > 0 && c == d) { ADD_NEW(state_offset + dlen + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_CHARI:
+ if (clen == 0) break;
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ if (c == d) { ADD_NEW(state_offset + dlen + 1, 0); } else
+ {
+ unsigned int othercase;
+ if (c < 128)
+ othercase = fcc[c];
+ else
+ othercase = UCD_OTHERCASE(c);
+ if (d == othercase) { ADD_NEW(state_offset + dlen + 1, 0); }
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ /* Not UTF mode */
+ {
+ if (TABLE_GET(c, lcc, c) == TABLE_GET(d, lcc, d))
+ { ADD_NEW(state_offset + 2, 0); }
+ }
+ break;
+
+
+#ifdef SUPPORT_UNICODE
+ /*-----------------------------------------------------------------*/
+ /* This is a tricky one because it can match more than one character.
+ Find out how many characters to skip, and then set up a negative state
+ to wait for them to pass before continuing. */
+
+ case OP_EXTUNI:
+ if (clen > 0)
+ {
+ int ncount = 0;
+ PCRE2_SPTR nptr = PRIV(extuni)(c, ptr + clen, mb->start_subject,
+ end_subject, utf, &ncount);
+ if (nptr >= end_subject && (mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ reset_could_continue = TRUE;
+ ADD_NEW_DATA(-(state_offset + 1), 0, ncount);
+ }
+ break;
+#endif
+
+ /*-----------------------------------------------------------------*/
+ /* This is a tricky like EXTUNI because it too can match more than one
+ character (when CR is followed by LF). In this case, set up a negative
+ state to wait for one character to pass before continuing. */
+
+ case OP_ANYNL:
+ if (clen > 0) switch(c)
+ {
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) break;
+ /* Fall through */
+
+ case CHAR_LF:
+ ADD_NEW(state_offset + 1, 0);
+ break;
+
+ case CHAR_CR:
+ if (ptr + 1 >= end_subject)
+ {
+ ADD_NEW(state_offset + 1, 0);
+ if ((mb->moptions & PCRE2_PARTIAL_HARD) != 0)
+ reset_could_continue = TRUE;
+ }
+ else if (UCHAR21TEST(ptr + 1) == CHAR_LF)
+ {
+ ADD_NEW_DATA(-(state_offset + 1), 0, 1);
+ }
+ else
+ {
+ ADD_NEW(state_offset + 1, 0);
+ }
+ break;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_NOT_VSPACE:
+ if (clen > 0) switch(c)
+ {
+ VSPACE_CASES:
+ break;
+
+ default:
+ ADD_NEW(state_offset + 1, 0);
+ break;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_VSPACE:
+ if (clen > 0) switch(c)
+ {
+ VSPACE_CASES:
+ ADD_NEW(state_offset + 1, 0);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_NOT_HSPACE:
+ if (clen > 0) switch(c)
+ {
+ HSPACE_CASES:
+ break;
+
+ default:
+ ADD_NEW(state_offset + 1, 0);
+ break;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_HSPACE:
+ if (clen > 0) switch(c)
+ {
+ HSPACE_CASES:
+ ADD_NEW(state_offset + 1, 0);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ /* Match a negated single character casefully. */
+
+ case OP_NOT:
+ if (clen > 0 && c != d) { ADD_NEW(state_offset + dlen + 1, 0); }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ /* Match a negated single character caselessly. */
+
+ case OP_NOTI:
+ if (clen > 0)
+ {
+ uint32_t otherd;
+#ifdef SUPPORT_UNICODE
+ if (utf && d >= 128)
+ otherd = UCD_OTHERCASE(d);
+ else
+#endif /* SUPPORT_UNICODE */
+ otherd = TABLE_GET(d, fcc, d);
+ if (c != d && c != otherd)
+ { ADD_NEW(state_offset + dlen + 1, 0); }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSPLUSI:
+ caseless = TRUE;
+ codevalue -= OP_STARI - OP_STAR;
+
+ /* Fall through */
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(state_offset + dlen + 1, 0); }
+ if (clen > 0)
+ {
+ uint32_t otherd = NOTACHAR;
+ if (caseless)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf && d >= 128)
+ otherd = UCD_OTHERCASE(d);
+ else
+#endif /* SUPPORT_UNICODE */
+ otherd = TABLE_GET(d, fcc, d);
+ }
+ if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+ {
+ if (count > 0 &&
+ (codevalue == OP_POSPLUS || codevalue == OP_NOTPOSPLUS))
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW(state_offset, count);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_POSQUERYI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTPOSQUERYI:
+ caseless = TRUE;
+ codevalue -= OP_STARI - OP_STAR;
+ /* Fall through */
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_POSQUERY:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTPOSQUERY:
+ ADD_ACTIVE(state_offset + dlen + 1, 0);
+ if (clen > 0)
+ {
+ uint32_t otherd = NOTACHAR;
+ if (caseless)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf && d >= 128)
+ otherd = UCD_OTHERCASE(d);
+ else
+#endif /* SUPPORT_UNICODE */
+ otherd = TABLE_GET(d, fcc, d);
+ }
+ if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+ {
+ if (codevalue == OP_POSQUERY || codevalue == OP_NOTPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(state_offset + dlen + 1, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_POSSTARI:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPOSSTARI:
+ caseless = TRUE;
+ codevalue -= OP_STARI - OP_STAR;
+ /* Fall through */
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_POSSTAR:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPOSSTAR:
+ ADD_ACTIVE(state_offset + dlen + 1, 0);
+ if (clen > 0)
+ {
+ uint32_t otherd = NOTACHAR;
+ if (caseless)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf && d >= 128)
+ otherd = UCD_OTHERCASE(d);
+ else
+#endif /* SUPPORT_UNICODE */
+ otherd = TABLE_GET(d, fcc, d);
+ }
+ if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+ {
+ if (codevalue == OP_POSSTAR || codevalue == OP_NOTPOSSTAR)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(state_offset, 0);
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_EXACTI:
+ case OP_NOTEXACTI:
+ caseless = TRUE;
+ codevalue -= OP_STARI - OP_STAR;
+ /* Fall through */
+ case OP_EXACT:
+ case OP_NOTEXACT:
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ uint32_t otherd = NOTACHAR;
+ if (caseless)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf && d >= 128)
+ otherd = UCD_OTHERCASE(d);
+ else
+#endif /* SUPPORT_UNICODE */
+ otherd = TABLE_GET(d, fcc, d);
+ }
+ if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+ {
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); }
+ else
+ { ADD_NEW(state_offset, count); }
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_POSUPTOI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTPOSUPTOI:
+ caseless = TRUE;
+ codevalue -= OP_STARI - OP_STAR;
+ /* Fall through */
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTPOSUPTO:
+ ADD_ACTIVE(state_offset + dlen + 1 + IMM2_SIZE, 0);
+ count = current_state->count; /* Number already matched */
+ if (clen > 0)
+ {
+ uint32_t otherd = NOTACHAR;
+ if (caseless)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf && d >= 128)
+ otherd = UCD_OTHERCASE(d);
+ else
+#endif /* SUPPORT_UNICODE */
+ otherd = TABLE_GET(d, fcc, d);
+ }
+ if ((c == d || c == otherd) == (codevalue < OP_NOTSTAR))
+ {
+ if (codevalue == OP_POSUPTO || codevalue == OP_NOTPOSUPTO)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ if (++count >= (int)GET2(code, 1))
+ { ADD_NEW(state_offset + dlen + 1 + IMM2_SIZE, 0); }
+ else
+ { ADD_NEW(state_offset, count); }
+ }
+ }
+ break;
+
+
+/* ========================================================================== */
+ /* These are the class-handling opcodes */
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ case OP_XCLASS:
+ {
+ BOOL isinclass = FALSE;
+ int next_state_offset;
+ PCRE2_SPTR ecode;
+
+ /* For a simple class, there is always just a 32-byte table, and we
+ can set isinclass from it. */
+
+ if (codevalue != OP_XCLASS)
+ {
+ ecode = code + 1 + (32 / sizeof(PCRE2_UCHAR));
+ if (clen > 0)
+ {
+ isinclass = (c > 255)? (codevalue == OP_NCLASS) :
+ ((((uint8_t *)(code + 1))[c/8] & (1 << (c&7))) != 0);
+ }
+ }
+
+ /* An extended class may have a table or a list of single characters,
+ ranges, or both, and it may be positive or negative. There's a
+ function that sorts all this out. */
+
+ else
+ {
+ ecode = code + GET(code, 1);
+ if (clen > 0) isinclass = PRIV(xclass)(c, code + 1 + LINK_SIZE, utf);
+ }
+
+ /* At this point, isinclass is set for all kinds of class, and ecode
+ points to the byte after the end of the class. If there is a
+ quantifier, this is where it will be. */
+
+ next_state_offset = (int)(ecode - start_code);
+
+ switch (*ecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPOSSTAR:
+ ADD_ACTIVE(next_state_offset + 1, 0);
+ if (isinclass)
+ {
+ if (*ecode == OP_CRPOSSTAR)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(state_offset, 0);
+ }
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ count = current_state->count; /* Already matched */
+ if (count > 0) { ADD_ACTIVE(next_state_offset + 1, 0); }
+ if (isinclass)
+ {
+ if (count > 0 && *ecode == OP_CRPOSPLUS)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ count++;
+ ADD_NEW(state_offset, count);
+ }
+ break;
+
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSQUERY:
+ ADD_ACTIVE(next_state_offset + 1, 0);
+ if (isinclass)
+ {
+ if (*ecode == OP_CRPOSQUERY)
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+ ADD_NEW(next_state_offset + 1, 0);
+ }
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ count = current_state->count; /* Already matched */
+ if (count >= (int)GET2(ecode, 1))
+ { ADD_ACTIVE(next_state_offset + 1 + 2 * IMM2_SIZE, 0); }
+ if (isinclass)
+ {
+ int max = (int)GET2(ecode, 1 + IMM2_SIZE);
+
+ if (*ecode == OP_CRPOSRANGE && count >= (int)GET2(ecode, 1))
+ {
+ active_count--; /* Remove non-match possibility */
+ next_active_state--;
+ }
+
+ if (++count >= max && max != 0) /* Max 0 => no limit */
+ { ADD_NEW(next_state_offset + 1 + 2 * IMM2_SIZE, 0); }
+ else
+ { ADD_NEW(state_offset, count); }
+ }
+ break;
+
+ default:
+ if (isinclass) { ADD_NEW(next_state_offset, 0); }
+ break;
+ }
+ }
+ break;
+
+/* ========================================================================== */
+ /* These are the opcodes for fancy brackets of various kinds. We have
+ to use recursion in order to handle them. The "always failing" assertion
+ (?!) is optimised to OP_FAIL when compiling, so we have to support that,
+ though the other "backtracking verbs" are not supported. */
+
+ case OP_FAIL:
+ forced_fail++; /* Count FAILs for multiple states */
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ {
+ int rc;
+ int *local_workspace;
+ PCRE2_SIZE *local_offsets;
+ PCRE2_SPTR endasscode = code + GET(code, 1);
+ RWS_anchor *rws = (RWS_anchor *)RWS;
+
+ if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+ {
+ rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+ if (rc != 0) return rc;
+ RWS = (int *)rws;
+ }
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
+
+ rc = internal_dfa_match(
+ mb, /* static match data */
+ code, /* this subexpression's code */
+ ptr, /* where we currently are */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
+ local_offsets, /* offset vector */
+ RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */
+ local_workspace, /* workspace vector */
+ RWS_RSIZE, /* size of same */
+ rlevel, /* function recursion level */
+ RWS); /* recursion workspace */
+
+ rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc;
+ if ((rc >= 0) == (codevalue == OP_ASSERT || codevalue == OP_ASSERTBACK))
+ { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_COND:
+ case OP_SCOND:
+ {
+ int codelink = (int)GET(code, 1);
+ PCRE2_UCHAR condcode;
+
+ /* Because of the way auto-callout works during compile, a callout item
+ is inserted between OP_COND and an assertion condition. This does not
+ happen for the other conditions. */
+
+ if (code[LINK_SIZE + 1] == OP_CALLOUT
+ || code[LINK_SIZE + 1] == OP_CALLOUT_STR)
+ {
+ PCRE2_SIZE callout_length;
+ rrc = do_callout(code, offsets, current_subject, ptr, mb,
+ 1 + LINK_SIZE, &callout_length);
+ if (rrc < 0) return rrc; /* Abandon */
+ if (rrc > 0) break; /* Fail this thread */
+ code += callout_length; /* Skip callout data */
+ }
+
+ condcode = code[LINK_SIZE+1];
+
+ /* Back reference conditions and duplicate named recursion conditions
+ are not supported */
+
+ if (condcode == OP_CREF || condcode == OP_DNCREF ||
+ condcode == OP_DNRREF)
+ return PCRE2_ERROR_DFA_UCOND;
+
+ /* The DEFINE condition is always false, and the assertion (?!) is
+ converted to OP_FAIL. */
+
+ if (condcode == OP_FALSE || condcode == OP_FAIL)
+ { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+
+ /* There is also an always-true condition */
+
+ else if (condcode == OP_TRUE)
+ { ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); }
+
+ /* The only supported version of OP_RREF is for the value RREF_ANY,
+ which means "test if in any recursion". We can't test for specifically
+ recursed groups. */
+
+ else if (condcode == OP_RREF)
+ {
+ unsigned int value = GET2(code, LINK_SIZE + 2);
+ if (value != RREF_ANY) return PCRE2_ERROR_DFA_UCOND;
+ if (mb->recursive != NULL)
+ { ADD_ACTIVE(state_offset + LINK_SIZE + 2 + IMM2_SIZE, 0); }
+ else { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+ }
+
+ /* Otherwise, the condition is an assertion */
+
+ else
+ {
+ int rc;
+ int *local_workspace;
+ PCRE2_SIZE *local_offsets;
+ PCRE2_SPTR asscode = code + LINK_SIZE + 1;
+ PCRE2_SPTR endasscode = asscode + GET(asscode, 1);
+ RWS_anchor *rws = (RWS_anchor *)RWS;
+
+ if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+ {
+ rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+ if (rc != 0) return rc;
+ RWS = (int *)rws;
+ }
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ while (*endasscode == OP_ALT) endasscode += GET(endasscode, 1);
+
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
+ asscode, /* this subexpression's code */
+ ptr, /* where we currently are */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
+ local_offsets, /* offset vector */
+ RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */
+ local_workspace, /* workspace vector */
+ RWS_RSIZE, /* size of same */
+ rlevel, /* function recursion level */
+ RWS); /* recursion workspace */
+
+ rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ if (rc < 0 && rc != PCRE2_ERROR_NOMATCH) return rc;
+ if ((rc >= 0) ==
+ (condcode == OP_ASSERT || condcode == OP_ASSERTBACK))
+ { ADD_ACTIVE((int)(endasscode + LINK_SIZE + 1 - start_code), 0); }
+ else
+ { ADD_ACTIVE(state_offset + codelink + LINK_SIZE + 1, 0); }
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_RECURSE:
+ {
+ int rc;
+ int *local_workspace;
+ PCRE2_SIZE *local_offsets;
+ RWS_anchor *rws = (RWS_anchor *)RWS;
+ dfa_recursion_info *ri;
+ PCRE2_SPTR callpat = start_code + GET(code, 1);
+ uint32_t recno = (callpat == mb->start_code)? 0 :
+ GET2(callpat, 1 + LINK_SIZE);
+
+ if (rws->free < RWS_RSIZE + RWS_OVEC_RSIZE)
+ {
+ rc = more_workspace(&rws, RWS_OVEC_RSIZE, mb);
+ if (rc != 0) return rc;
+ RWS = (int *)rws;
+ }
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_RSIZE;
+ rws->free -= RWS_RSIZE + RWS_OVEC_RSIZE;
+
+ /* Check for repeating a recursion without advancing the subject
+ pointer. This should catch convoluted mutual recursions. (Some simple
+ cases are caught at compile time.) */
+
+ for (ri = mb->recursive; ri != NULL; ri = ri->prevrec)
+ if (recno == ri->group_num && ptr == ri->subject_position)
+ return PCRE2_ERROR_RECURSELOOP;
+
+ /* Remember this recursion and where we started it so as to
+ catch infinite loops. */
+
+ new_recursive.group_num = recno;
+ new_recursive.subject_position = ptr;
+ new_recursive.prevrec = mb->recursive;
+ mb->recursive = &new_recursive;
+
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
+ callpat, /* this subexpression's code */
+ ptr, /* where we currently are */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
+ local_offsets, /* offset vector */
+ RWS_OVEC_RSIZE/OVEC_UNIT, /* size of same */
+ local_workspace, /* workspace vector */
+ RWS_RSIZE, /* size of same */
+ rlevel, /* function recursion level */
+ RWS); /* recursion workspace */
+
+ rws->free += RWS_RSIZE + RWS_OVEC_RSIZE;
+ mb->recursive = new_recursive.prevrec; /* Done this recursion */
+
+ /* Ran out of internal offsets */
+
+ if (rc == 0) return PCRE2_ERROR_DFA_RECURSE;
+
+ /* For each successful matched substring, set up the next state with a
+ count of characters to skip before trying it. Note that the count is in
+ characters, not bytes. */
+
+ if (rc > 0)
+ {
+ for (rc = rc*2 - 2; rc >= 0; rc -= 2)
+ {
+ PCRE2_SIZE charcount = local_offsets[rc+1] - local_offsets[rc];
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf)
+ {
+ PCRE2_SPTR p = start_subject + local_offsets[rc];
+ PCRE2_SPTR pp = start_subject + local_offsets[rc+1];
+ while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
+ }
+#endif
+ if (charcount > 0)
+ {
+ ADD_NEW_DATA(-(state_offset + LINK_SIZE + 1), 0,
+ (int)(charcount - 1));
+ }
+ else
+ {
+ ADD_ACTIVE(state_offset + LINK_SIZE + 1, 0);
+ }
+ }
+ }
+ else if (rc != PCRE2_ERROR_NOMATCH) return rc;
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_BRAPOSZERO:
+ {
+ int rc;
+ int *local_workspace;
+ PCRE2_SIZE *local_offsets;
+ PCRE2_SIZE charcount, matched_count;
+ PCRE2_SPTR local_ptr = ptr;
+ RWS_anchor *rws = (RWS_anchor *)RWS;
+ BOOL allow_zero;
+
+ if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+ {
+ rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+ if (rc != 0) return rc;
+ RWS = (int *)rws;
+ }
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ if (codevalue == OP_BRAPOSZERO)
+ {
+ allow_zero = TRUE;
+ codevalue = *(++code); /* Codevalue will be one of above BRAs */
+ }
+ else allow_zero = FALSE;
+
+ /* Loop to match the subpattern as many times as possible as if it were
+ a complete pattern. */
+
+ for (matched_count = 0;; matched_count++)
+ {
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
+ code, /* this subexpression's code */
+ local_ptr, /* where we currently are */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
+ local_offsets, /* offset vector */
+ RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */
+ local_workspace, /* workspace vector */
+ RWS_RSIZE, /* size of same */
+ rlevel, /* function recursion level */
+ RWS); /* recursion workspace */
+
+ /* Failed to match */
+
+ if (rc < 0)
+ {
+ if (rc != PCRE2_ERROR_NOMATCH) return rc;
+ break;
+ }
+
+ /* Matched: break the loop if zero characters matched. */
+
+ charcount = local_offsets[1] - local_offsets[0];
+ if (charcount == 0) break;
+ local_ptr += charcount; /* Advance temporary position ptr */
+ }
+
+ rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ /* At this point we have matched the subpattern matched_count
+ times, and local_ptr is pointing to the character after the end of the
+ last match. */
+
+ if (matched_count > 0 || allow_zero)
+ {
+ PCRE2_SPTR end_subpattern = code;
+ int next_state_offset;
+
+ do { end_subpattern += GET(end_subpattern, 1); }
+ while (*end_subpattern == OP_ALT);
+ next_state_offset =
+ (int)(end_subpattern - start_code + LINK_SIZE + 1);
+
+ /* Optimization: if there are no more active states, and there
+ are no new states yet set up, then skip over the subject string
+ right here, to save looping. Otherwise, set up the new state to swing
+ into action when the end of the matched substring is reached. */
+
+ if (i + 1 >= active_count && new_count == 0)
+ {
+ ptr = local_ptr;
+ clen = 0;
+ ADD_NEW(next_state_offset, 0);
+ }
+ else
+ {
+ PCRE2_SPTR p = ptr;
+ PCRE2_SPTR pp = local_ptr;
+ charcount = (PCRE2_SIZE)(pp - p);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf) while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
+#endif
+ ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1));
+ }
+ }
+ }
+ break;
+
+ /*-----------------------------------------------------------------*/
+ case OP_ONCE:
+ {
+ int rc;
+ int *local_workspace;
+ PCRE2_SIZE *local_offsets;
+ RWS_anchor *rws = (RWS_anchor *)RWS;
+
+ if (rws->free < RWS_RSIZE + RWS_OVEC_OSIZE)
+ {
+ rc = more_workspace(&rws, RWS_OVEC_OSIZE, mb);
+ if (rc != 0) return rc;
+ RWS = (int *)rws;
+ }
+
+ local_offsets = (PCRE2_SIZE *)(RWS + rws->size - rws->free);
+ local_workspace = ((int *)local_offsets) + RWS_OVEC_OSIZE;
+ rws->free -= RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
+ code, /* this subexpression's code */
+ ptr, /* where we currently are */
+ (PCRE2_SIZE)(ptr - start_subject), /* start offset */
+ local_offsets, /* offset vector */
+ RWS_OVEC_OSIZE/OVEC_UNIT, /* size of same */
+ local_workspace, /* workspace vector */
+ RWS_RSIZE, /* size of same */
+ rlevel, /* function recursion level */
+ RWS); /* recursion workspace */
+
+ rws->free += RWS_RSIZE + RWS_OVEC_OSIZE;
+
+ if (rc >= 0)
+ {
+ PCRE2_SPTR end_subpattern = code;
+ PCRE2_SIZE charcount = local_offsets[1] - local_offsets[0];
+ int next_state_offset, repeat_state_offset;
+
+ do { end_subpattern += GET(end_subpattern, 1); }
+ while (*end_subpattern == OP_ALT);
+ next_state_offset =
+ (int)(end_subpattern - start_code + LINK_SIZE + 1);
+
+ /* If the end of this subpattern is KETRMAX or KETRMIN, we must
+ arrange for the repeat state also to be added to the relevant list.
+ Calculate the offset, or set -1 for no repeat. */
+
+ repeat_state_offset = (*end_subpattern == OP_KETRMAX ||
+ *end_subpattern == OP_KETRMIN)?
+ (int)(end_subpattern - start_code - GET(end_subpattern, 1)) : -1;
+
+ /* If we have matched an empty string, add the next state at the
+ current character pointer. This is important so that the duplicate
+ checking kicks in, which is what breaks infinite loops that match an
+ empty string. */
+
+ if (charcount == 0)
+ {
+ ADD_ACTIVE(next_state_offset, 0);
+ }
+
+ /* Optimization: if there are no more active states, and there
+ are no new states yet set up, then skip over the subject string
+ right here, to save looping. Otherwise, set up the new state to swing
+ into action when the end of the matched substring is reached. */
+
+ else if (i + 1 >= active_count && new_count == 0)
+ {
+ ptr += charcount;
+ clen = 0;
+ ADD_NEW(next_state_offset, 0);
+
+ /* If we are adding a repeat state at the new character position,
+ we must fudge things so that it is the only current state.
+ Otherwise, it might be a duplicate of one we processed before, and
+ that would cause it to be skipped. */
+
+ if (repeat_state_offset >= 0)
+ {
+ next_active_state = active_states;
+ active_count = 0;
+ i = -1;
+ ADD_ACTIVE(repeat_state_offset, 0);
+ }
+ }
+ else
+ {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (utf)
+ {
+ PCRE2_SPTR p = start_subject + local_offsets[0];
+ PCRE2_SPTR pp = start_subject + local_offsets[1];
+ while (p < pp) if (NOT_FIRSTCU(*p++)) charcount--;
+ }
+#endif
+ ADD_NEW_DATA(-next_state_offset, 0, (int)(charcount - 1));
+ if (repeat_state_offset >= 0)
+ { ADD_NEW_DATA(-repeat_state_offset, 0, (int)(charcount - 1)); }
+ }
+ }
+ else if (rc != PCRE2_ERROR_NOMATCH) return rc;
+ }
+ break;
+
+
+/* ========================================================================== */
+ /* Handle callouts */
+
+ case OP_CALLOUT:
+ case OP_CALLOUT_STR:
+ {
+ PCRE2_SIZE callout_length;
+ rrc = do_callout(code, offsets, current_subject, ptr, mb, 0,
+ &callout_length);
+ if (rrc < 0) return rrc; /* Abandon */
+ if (rrc == 0)
+ { ADD_ACTIVE(state_offset + (int)callout_length, 0); }
+ }
+ break;
+
+
+/* ========================================================================== */
+ default: /* Unsupported opcode */
+ return PCRE2_ERROR_DFA_UITEM;
+ }
+
+ NEXT_ACTIVE_STATE: continue;
+
+ } /* End of loop scanning active states */
+
+ /* We have finished the processing at the current subject character. If no
+ new states have been set for the next character, we have found all the
+ matches that we are going to find. If we are at the top level and partial
+ matching has been requested, check for appropriate conditions.
+
+ The "forced_ fail" variable counts the number of (*F) encountered for the
+ character. If it is equal to the original active_count (saved in
+ workspace[1]) it means that (*F) was found on every active state. In this
+ case we don't want to give a partial match.
+
+ The "could_continue" variable is true if a state could have continued but
+ for the fact that the end of the subject was reached. */
+
+ if (new_count <= 0)
+ {
+ if (rlevel == 1 && /* Top level, and */
+ could_continue && /* Some could go on, and */
+ forced_fail != workspace[1] && /* Not all forced fail & */
+ ( /* either... */
+ (mb->moptions & PCRE2_PARTIAL_HARD) != 0 /* Hard partial */
+ || /* or... */
+ ((mb->moptions & PCRE2_PARTIAL_SOFT) != 0 && /* Soft partial and */
+ match_count < 0) /* no matches */
+ ) && /* And... */
+ (
+ partial_newline || /* Either partial NL */
+ ( /* or ... */
+ ptr >= end_subject && /* End of subject and */
+ ptr > mb->start_used_ptr) /* Inspected non-empty string */
+ )
+ )
+ match_count = PCRE2_ERROR_PARTIAL;
+ break; /* Exit from loop along the subject string */
+ }
+
+ /* One or more states are active for the next character. */
+
+ ptr += clen; /* Advance to next subject character */
+ } /* Loop to move along the subject string */
+
+/* Control gets here from "break" a few lines above. If we have a match and
+PCRE2_ENDANCHORED is set, the match fails. */
+
+if (match_count >= 0 &&
+ ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0 &&
+ ptr < end_subject)
+ match_count = PCRE2_ERROR_NOMATCH;
+
+return match_count;
+}
+
+
+
+/*************************************************
+* Match a pattern using the DFA algorithm *
+*************************************************/
+
+/* This function matches a compiled pattern to a subject string, using the
+alternate matching algorithm that finds all matches at once.
+
+Arguments:
+ code points to the compiled pattern
+ subject subject string
+ length length of subject string
+ startoffset where to start matching in the subject
+ options option bits
+ match_data points to a match data structure
+ gcontext points to a match context
+ workspace pointer to workspace
+ wscount size of workspace
+
+Returns: > 0 => number of match offset pairs placed in offsets
+ = 0 => offsets overflowed; longest matches are present
+ -1 => failed to match
+ < -1 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_dfa_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext, int *workspace, PCRE2_SIZE wscount)
+{
+int rc;
+const pcre2_real_code *re = (const pcre2_real_code *)code;
+
+PCRE2_SPTR start_match;
+PCRE2_SPTR end_subject;
+PCRE2_SPTR bumpalong_limit;
+PCRE2_SPTR req_cu_ptr;
+
+BOOL utf, anchored, startline, firstline;
+BOOL has_first_cu = FALSE;
+BOOL has_req_cu = FALSE;
+
+PCRE2_UCHAR first_cu = 0;
+PCRE2_UCHAR first_cu2 = 0;
+PCRE2_UCHAR req_cu = 0;
+PCRE2_UCHAR req_cu2 = 0;
+
+const uint8_t *start_bits = NULL;
+
+/* We need to have mb pointing to a match block, because the IS_NEWLINE macro
+is used below, and it expects NLBLOCK to be defined as a pointer. */
+
+pcre2_callout_block cb;
+dfa_match_block actual_match_block;
+dfa_match_block *mb = &actual_match_block;
+
+/* Set up a starting block of memory for use during recursive calls to
+internal_dfa_match(). By putting this on the stack, it minimizes resource use
+in the case when it is not needed. If this is too small, more memory is
+obtained from the heap. At the start of each block is an anchor structure.*/
+
+int base_recursion_workspace[RWS_BASE_SIZE];
+RWS_anchor *rws = (RWS_anchor *)base_recursion_workspace;
+rws->next = NULL;
+rws->size = RWS_BASE_SIZE;
+rws->free = RWS_BASE_SIZE - RWS_ANCHOR_SIZE;
+
+/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
+subject string. */
+
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
+
+/* Plausibility checks */
+
+if ((options & ~PUBLIC_DFA_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
+if (re == NULL || subject == NULL || workspace == NULL || match_data == NULL)
+ return PCRE2_ERROR_NULL;
+if (wscount < 20) return PCRE2_ERROR_DFA_WSSIZE;
+if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+
+/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same
+time. */
+
+if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0 &&
+ ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
+ return PCRE2_ERROR_BADOPTION;
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check the code unit width. */
+
+if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
+ return PCRE2_ERROR_BADMODE;
+
+/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
+options variable for this function. Users of PCRE2 who are not calling the
+function directly would like to have a way of setting these flags, in the same
+way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with
+constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and
+(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which can now be
+transferred to the options for this function. The bits are guaranteed to be
+adjacent, but do not have the same values. This bit of Boolean trickery assumes
+that the match-time bits are not more significant than the flag bits. If by
+accident this is not the case, a compile-time division by zero error will
+occur. */
+
+#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET)
+#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART)
+options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+#undef FF
+#undef OO
+
+/* If restarting after a partial match, do some sanity checks on the contents
+of the workspace. */
+
+if ((options & PCRE2_DFA_RESTART) != 0)
+ {
+ if ((workspace[0] & (-2)) != 0 || workspace[1] < 1 ||
+ workspace[1] > (int)((wscount - 2)/INTS_PER_STATEBLOCK))
+ return PCRE2_ERROR_DFA_BADRESTART;
+ }
+
+/* Set some local values */
+
+utf = (re->overall_options & PCRE2_UTF) != 0;
+start_match = subject + start_offset;
+end_subject = subject + length;
+req_cu_ptr = start_match - 1;
+anchored = (options & (PCRE2_ANCHORED|PCRE2_DFA_RESTART)) != 0 ||
+ (re->overall_options & PCRE2_ANCHORED) != 0;
+
+/* The "must be at the start of a line" flags are used in a loop when finding
+where to start. */
+
+startline = (re->flags & PCRE2_STARTLINE) != 0;
+firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+bumpalong_limit = end_subject;
+
+/* Initialize and set up the fixed fields in the callout block, with a pointer
+in the match block. */
+
+mb->cb = &cb;
+cb.version = 2;
+cb.subject = subject;
+cb.subject_length = (PCRE2_SIZE)(end_subject - subject);
+cb.callout_flags = 0;
+cb.capture_top = 1; /* No capture support */
+cb.capture_last = 0;
+cb.mark = NULL; /* No (*MARK) support */
+
+/* Get data from the match context, if present, and fill in the remaining
+fields in the match block. It is an error to set an offset limit without
+setting the flag at compile time. */
+
+if (mcontext == NULL)
+ {
+ mb->callout = NULL;
+ mb->memctl = re->memctl;
+ mb->match_limit = PRIV(default_match_context).match_limit;
+ mb->match_limit_depth = PRIV(default_match_context).depth_limit;
+ mb->heap_limit = PRIV(default_match_context).heap_limit;
+ }
+else
+ {
+ if (mcontext->offset_limit != PCRE2_UNSET)
+ {
+ if ((re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
+ return PCRE2_ERROR_BADOFFSETLIMIT;
+ bumpalong_limit = subject + mcontext->offset_limit;
+ }
+ mb->callout = mcontext->callout;
+ mb->callout_data = mcontext->callout_data;
+ mb->memctl = mcontext->memctl;
+ mb->match_limit = mcontext->match_limit;
+ mb->match_limit_depth = mcontext->depth_limit;
+ mb->heap_limit = mcontext->heap_limit;
+ }
+
+if (mb->match_limit > re->limit_match)
+ mb->match_limit = re->limit_match;
+
+if (mb->match_limit_depth > re->limit_depth)
+ mb->match_limit_depth = re->limit_depth;
+
+if (mb->heap_limit > re->limit_heap)
+ mb->heap_limit = re->limit_heap;
+
+mb->start_code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ re->name_count * re->name_entry_size;
+mb->tables = re->tables;
+mb->start_subject = subject;
+mb->end_subject = end_subject;
+mb->start_offset = start_offset;
+mb->moptions = options;
+mb->poptions = re->overall_options;
+mb->match_call_count = 0;
+mb->heap_used = 0;
+
+/* Process the \R and newline settings. */
+
+mb->bsr_convention = re->bsr_convention;
+mb->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+ {
+ case PCRE2_NEWLINE_CR:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_CR;
+ break;
+
+ case PCRE2_NEWLINE_LF:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_NUL:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_NUL;
+ break;
+
+ case PCRE2_NEWLINE_CRLF:
+ mb->nllen = 2;
+ mb->nl[0] = CHAR_CR;
+ mb->nl[1] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_ANY:
+ mb->nltype = NLTYPE_ANY;
+ break;
+
+ case PCRE2_NEWLINE_ANYCRLF:
+ mb->nltype = NLTYPE_ANYCRLF;
+ break;
+
+ default: return PCRE2_ERROR_INTERNAL;
+ }
+
+/* Check a UTF string for validity if required. For 8-bit and 16-bit strings,
+we must also check that a starting offset does not point into the middle of a
+multiunit character. We check only the portion of the subject that is going to
+be inspected during matching - from the offset minus the maximum back reference
+to the given length. This saves time when a small part of a large subject is
+being matched by the use of a starting offset. Note that the maximum lookbehind
+is a number of characters, not code units. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
+ {
+ PCRE2_SPTR check_subject = start_match; /* start_match includes offset */
+
+ if (start_offset > 0)
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ unsigned int i;
+ if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+ return PCRE2_ERROR_BADUTFOFFSET;
+ for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
+ {
+ check_subject--;
+ while (check_subject > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ (*check_subject & 0xc0) == 0x80)
+#else /* 16-bit */
+ (*check_subject & 0xfc00) == 0xdc00)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ check_subject--;
+ }
+#else /* In the 32-bit library, one code unit equals one character. */
+ check_subject -= re->max_lookbehind;
+ if (check_subject < subject) check_subject = subject;
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+ }
+
+ /* Validate the relevant portion of the subject. After an error, adjust the
+ offset to be an absolute offset in the whole string. */
+
+ match_data->rc = PRIV(valid_utf)(check_subject,
+ length - (PCRE2_SIZE)(check_subject - subject), &(match_data->startchar));
+ if (match_data->rc != 0)
+ {
+ match_data->startchar += (PCRE2_SIZE)(check_subject - subject);
+ return match_data->rc;
+ }
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* Set up the first code unit to match, if available. If there's no first code
+unit there may be a bitmap of possible first characters. */
+
+if ((re->flags & PCRE2_FIRSTSET) != 0)
+ {
+ has_first_cu = TRUE;
+ first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit);
+ if ((re->flags & PCRE2_FIRSTCASELESS) != 0)
+ {
+ first_cu2 = TABLE_GET(first_cu, mb->tables + fcc_offset, first_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && first_cu > 127)
+ first_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(first_cu);
+#endif
+ }
+ }
+else
+ if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0)
+ start_bits = re->start_bitmap;
+
+/* There may be a "last known required code unit" set. */
+
+if ((re->flags & PCRE2_LASTSET) != 0)
+ {
+ has_req_cu = TRUE;
+ req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit);
+ if ((re->flags & PCRE2_LASTCASELESS) != 0)
+ {
+ req_cu2 = TABLE_GET(req_cu, mb->tables + fcc_offset, req_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && req_cu > 127) req_cu2 = (PCRE2_UCHAR)UCD_OTHERCASE(req_cu);
+#endif
+ }
+ }
+
+/* Fill in fields that are always returned in the match data. */
+
+match_data->code = re;
+match_data->subject = subject;
+match_data->mark = NULL;
+match_data->matchedby = PCRE2_MATCHEDBY_DFA_INTERPRETER;
+
+/* Call the main matching function, looping for a non-anchored regex after a
+failed match. If not restarting, perform certain optimizations at the start of
+a match. */
+
+for (;;)
+ {
+ /* ----------------- Start of match optimizations ---------------- */
+
+ /* There are some optimizations that avoid running the match if a known
+ starting point is not found, or if a known later code unit is not present.
+ However, there is an option (settable at compile time) that disables
+ these, for testing and for ensuring that all callouts do actually occur.
+ The optimizations must also be avoided when restarting a DFA match. */
+
+ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0 &&
+ (options & PCRE2_DFA_RESTART) == 0)
+ {
+ /* If firstline is TRUE, the start of the match is constrained to the first
+ line of a multiline string. That is, the match must be before or at the
+ first newline following the start of matching. Temporarily adjust
+ end_subject so that we stop the optimization scans for a first code unit
+ immediately after the first character of a newline (the first code unit can
+ legitimately be a newline). If the match fails at the newline, later code
+ breaks this loop. */
+
+ if (firstline)
+ {
+ PCRE2_SPTR t = start_match;
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ while (t < end_subject && !IS_NEWLINE(t))
+ {
+ t++;
+ ACROSSCHAR(t < end_subject, t, t++);
+ }
+ }
+ else
+#endif
+ while (t < end_subject && !IS_NEWLINE(t)) t++;
+ end_subject = t;
+ }
+
+ /* Anchored: check the first code unit if one is recorded. This may seem
+ pointless but it can help in detecting a no match case without scanning for
+ the required code unit. */
+
+ if (anchored)
+ {
+ if (has_first_cu || start_bits != NULL)
+ {
+ BOOL ok = start_match < end_subject;
+ if (ok)
+ {
+ PCRE2_UCHAR c = UCHAR21TEST(start_match);
+ ok = has_first_cu && (c == first_cu || c == first_cu2);
+ if (!ok && start_bits != NULL)
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (c > 255) c = 255;
+#endif
+ ok = (start_bits[c/8] & (1 << (c&7))) != 0;
+ }
+ }
+ if (!ok) break;
+ }
+ }
+
+ /* Not anchored. Advance to a unique first code unit if there is one. In
+ 8-bit mode, the use of memchr() gives a big speed up, even though we have
+ to call it twice in caseless mode, in order to find the earliest occurrence
+ of the character in either of its cases. */
+
+ else
+ {
+ if (has_first_cu)
+ {
+ if (first_cu != first_cu2) /* Caseless */
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ PCRE2_UCHAR smc;
+ while (start_match < end_subject &&
+ (smc = UCHAR21TEST(start_match)) != first_cu &&
+ smc != first_cu2)
+ start_match++;
+#else /* 8-bit code units */
+ PCRE2_SPTR pp1 =
+ memchr(start_match, first_cu, end_subject-start_match);
+ PCRE2_SPTR pp2 =
+ memchr(start_match, first_cu2, end_subject-start_match);
+ if (pp1 == NULL)
+ start_match = (pp2 == NULL)? end_subject : pp2;
+ else
+ start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
+#endif
+ }
+
+ /* The caseful case */
+
+ else
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ while (start_match < end_subject && UCHAR21TEST(start_match) !=
+ first_cu)
+ start_match++;
+#else
+ start_match = memchr(start_match, first_cu, end_subject - start_match);
+ if (start_match == NULL) start_match = end_subject;
+#endif
+ }
+
+ /* If we can't find the required code unit, having reached the true end
+ of the subject, break the bumpalong loop, to force a match failure,
+ except when doing partial matching, when we let the next cycle run at
+ the end of the subject. To see why, consider the pattern /(?<=abc)def/,
+ which partially matches "abc", even though the string does not contain
+ the starting character "d". If we have not reached the true end of the
+ subject (PCRE2_FIRSTLINE caused end_subject to be temporarily modified)
+ we also let the cycle run, because the matching string is legitimately
+ allowed to start with the first code unit of a newline. */
+
+ if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 &&
+ start_match >= mb->end_subject)
+ break;
+ }
+
+ /* If there's no first code unit, advance to just after a linebreak for a
+ multiline match if required. */
+
+ else if (startline)
+ {
+ if (start_match > mb->start_subject + start_offset)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ while (start_match < end_subject && !WAS_NEWLINE(start_match))
+ {
+ start_match++;
+ ACROSSCHAR(start_match < end_subject, start_match, start_match++);
+ }
+ }
+ else
+#endif
+ while (start_match < end_subject && !WAS_NEWLINE(start_match))
+ start_match++;
+
+ /* If we have just passed a CR and the newline option is ANY or
+ ANYCRLF, and we are now at a LF, advance the match position by one
+ more code unit. */
+
+ if (start_match[-1] == CHAR_CR &&
+ (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) &&
+ start_match < end_subject &&
+ UCHAR21TEST(start_match) == CHAR_NL)
+ start_match++;
+ }
+ }
+
+ /* If there's no first code unit or a requirement for a multiline line
+ start, advance to a non-unique first code unit if any have been
+ identified. The bitmap contains only 256 bits. When code units are 16 or
+ 32 bits wide, all code units greater than 254 set the 255 bit. */
+
+ else if (start_bits != NULL)
+ {
+ while (start_match < end_subject)
+ {
+ uint32_t c = UCHAR21TEST(start_match);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (c > 255) c = 255;
+#endif
+ if ((start_bits[c/8] & (1 << (c&7))) != 0) break;
+ start_match++;
+ }
+
+ /* See comment above in first_cu checking about the next line. */
+
+ if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0 &&
+ start_match >= mb->end_subject)
+ break;
+ }
+ } /* End of first code unit handling */
+
+ /* Restore fudged end_subject */
+
+ end_subject = mb->end_subject;
+
+ /* The following two optimizations are disabled for partial matching. */
+
+ if ((mb->moptions & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) == 0)
+ {
+ /* The minimum matching length is a lower bound; no actual string of that
+ length may actually match the pattern. Although the value is, strictly,
+ in characters, we treat it as code units to avoid spending too much time
+ in this optimization. */
+
+ if (end_subject - start_match < re->minlength) goto NOMATCH_EXIT;
+
+ /* If req_cu is set, we know that that code unit must appear in the
+ subject for the match to succeed. If the first code unit is set, req_cu
+ must be later in the subject; otherwise the test starts at the match
+ point. This optimization can save a huge amount of backtracking in
+ patterns with nested unlimited repeats that aren't going to match.
+ Writing separate code for cased/caseless versions makes it go faster, as
+ does using an autoincrement and backing off on a match.
+
+ HOWEVER: when the subject string is very, very long, searching to its end
+ can take a long time, and give bad performance on quite ordinary
+ patterns. This showed up when somebody was matching something like
+ /^\d+C/ on a 32-megabyte string... so we don't do this when the string is
+ sufficiently long. */
+
+ if (has_req_cu && end_subject - start_match < REQ_CU_MAX)
+ {
+ PCRE2_SPTR p = start_match + (has_first_cu? 1:0);
+
+ /* We don't need to repeat the search if we haven't yet reached the
+ place we found it at last time. */
+
+ if (p > req_cu_ptr)
+ {
+ if (req_cu != req_cu2)
+ {
+ while (p < end_subject)
+ {
+ uint32_t pp = UCHAR21INCTEST(p);
+ if (pp == req_cu || pp == req_cu2) { p--; break; }
+ }
+ }
+ else
+ {
+ while (p < end_subject)
+ {
+ if (UCHAR21INCTEST(p) == req_cu) { p--; break; }
+ }
+ }
+
+ /* If we can't find the required code unit, break the matching loop,
+ forcing a match failure. */
+
+ if (p >= end_subject) break;
+
+ /* If we have found the required code unit, save the point where we
+ found it, so that we don't search again next time round the loop if
+ the start hasn't passed this code unit yet. */
+
+ req_cu_ptr = p;
+ }
+ }
+ }
+ }
+
+ /* ------------ End of start of match optimizations ------------ */
+
+ /* Give no match if we have passed the bumpalong limit. */
+
+ if (start_match > bumpalong_limit) break;
+
+ /* OK, now we can do the business */
+
+ mb->start_used_ptr = start_match;
+ mb->last_used_ptr = start_match;
+ mb->recursive = NULL;
+
+ rc = internal_dfa_match(
+ mb, /* fixed match data */
+ mb->start_code, /* this subexpression's code */
+ start_match, /* where we currently are */
+ start_offset, /* start offset in subject */
+ match_data->ovector, /* offset vector */
+ (uint32_t)match_data->oveccount * 2, /* actual size of same */
+ workspace, /* workspace vector */
+ (int)wscount, /* size of same */
+ 0, /* function recurse level */
+ base_recursion_workspace); /* initial workspace for recursion */
+
+ /* Anything other than "no match" means we are done, always; otherwise, carry
+ on only if not anchored. */
+
+ if (rc != PCRE2_ERROR_NOMATCH || anchored)
+ {
+ if (rc == PCRE2_ERROR_PARTIAL && match_data->oveccount > 0)
+ {
+ match_data->ovector[0] = (PCRE2_SIZE)(start_match - subject);
+ match_data->ovector[1] = (PCRE2_SIZE)(end_subject - subject);
+ }
+ match_data->leftchar = (PCRE2_SIZE)(mb->start_used_ptr - subject);
+ match_data->rightchar = (PCRE2_SIZE)( mb->last_used_ptr - subject);
+ match_data->startchar = (PCRE2_SIZE)(start_match - subject);
+ match_data->rc = rc;
+ goto EXIT;
+ }
+
+ /* Advance to the next subject character unless we are at the end of a line
+ and firstline is set. */
+
+ if (firstline && IS_NEWLINE(start_match)) break;
+ start_match++;
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ ACROSSCHAR(start_match < end_subject, start_match, start_match++);
+ }
+#endif
+ if (start_match > end_subject) break;
+
+ /* If we have just passed a CR and we are now at a LF, and the pattern does
+ not contain any explicit matches for \r or \n, and the newline option is CRLF
+ or ANY or ANYCRLF, advance the match position by one more character. */
+
+ if (UCHAR21TEST(start_match - 1) == CHAR_CR &&
+ start_match < end_subject &&
+ UCHAR21TEST(start_match) == CHAR_NL &&
+ (re->flags & PCRE2_HASCRORLF) == 0 &&
+ (mb->nltype == NLTYPE_ANY ||
+ mb->nltype == NLTYPE_ANYCRLF ||
+ mb->nllen == 2))
+ start_match++;
+
+ } /* "Bumpalong" loop */
+
+NOMATCH_EXIT:
+rc = PCRE2_ERROR_NOMATCH;
+
+EXIT:
+while (rws->next != NULL)
+ {
+ RWS_anchor *next = rws->next;
+ rws->next = next->next;
+ mb->memctl.free(next, mb->memctl.memory_data);
+ }
+
+return rc;
+}
+
+/* End of pcre2_dfa_match.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_error.c b/test/monniaux/pcre2-10.32/pcre2_error.c
new file mode 100644
index 00000000..4b3b3f1b
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_error.c
@@ -0,0 +1,334 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define STRING(a) # a
+#define XSTRING(s) STRING(s)
+
+/* The texts of compile-time error messages. Compile-time error numbers start
+at COMPILE_ERROR_BASE (100).
+
+This used to be a table of strings, but in order to reduce the number of
+relocations needed when a shared library is loaded dynamically, it is now one
+long string. We cannot use a table of offsets, because the lengths of inserts
+such as XSTRING(MAX_NAME_SIZE) are not known. Instead,
+pcre2_get_error_message() counts through to the one it wants - this isn't a
+performance issue because these strings are used only when there is an error.
+
+Each substring ends with \0 to insert a null character. This includes the final
+substring, so that the whole string ends with \0\0, which can be detected when
+counting through. */
+
+static const unsigned char compile_error_texts[] =
+ "no error\0"
+ "\\ at end of pattern\0"
+ "\\c at end of pattern\0"
+ "unrecognized character follows \\\0"
+ "numbers out of order in {} quantifier\0"
+ /* 5 */
+ "number too big in {} quantifier\0"
+ "missing terminating ] for character class\0"
+ "invalid escape sequence in character class\0"
+ "range out of order in character class\0"
+ "quantifier does not follow a repeatable item\0"
+ /* 10 */
+ "internal error: unexpected repeat\0"
+ "unrecognized character after (? or (?-\0"
+ "POSIX named classes are supported only within a class\0"
+ "POSIX collating elements are not supported\0"
+ "missing closing parenthesis\0"
+ /* 15 */
+ "reference to non-existent subpattern\0"
+ "pattern passed as NULL\0"
+ "unrecognised compile-time option bit(s)\0"
+ "missing ) after (?# comment\0"
+ "parentheses are too deeply nested\0"
+ /* 20 */
+ "regular expression is too large\0"
+ "failed to allocate heap memory\0"
+ "unmatched closing parenthesis\0"
+ "internal error: code overflow\0"
+ "missing closing parenthesis for condition\0"
+ /* 25 */
+ "lookbehind assertion is not fixed length\0"
+ "a relative value of zero is not allowed\0"
+ "conditional group contains more than two branches\0"
+ "assertion expected after (?( or (?(?C)\0"
+ "digit expected after (?+ or (?-\0"
+ /* 30 */
+ "unknown POSIX class name\0"
+ "internal error in pcre2_study(): should not occur\0"
+ "this version of PCRE2 does not have Unicode support\0"
+ "parentheses are too deeply nested (stack check)\0"
+ "character code point value in \\x{} or \\o{} is too large\0"
+ /* 35 */
+ "lookbehind is too complicated\0"
+ "\\C is not allowed in a lookbehind assertion in UTF-" XSTRING(PCRE2_CODE_UNIT_WIDTH) " mode\0"
+ "PCRE2 does not support \\F, \\L, \\l, \\N{name}, \\U, or \\u\0"
+ "number after (?C is greater than 255\0"
+ "closing parenthesis for (?C expected\0"
+ /* 40 */
+ "invalid escape sequence in (*VERB) name\0"
+ "unrecognized character after (?P\0"
+ "syntax error in subpattern name (missing terminator)\0"
+ "two named subpatterns have the same name (PCRE2_DUPNAMES not set)\0"
+ "group name must start with a non-digit\0"
+ /* 45 */
+ "this version of PCRE2 does not have support for \\P, \\p, or \\X\0"
+ "malformed \\P or \\p sequence\0"
+ "unknown property name after \\P or \\p\0"
+ "subpattern name is too long (maximum " XSTRING(MAX_NAME_SIZE) " characters)\0"
+ "too many named subpatterns (maximum " XSTRING(MAX_NAME_COUNT) ")\0"
+ /* 50 */
+ "invalid range in character class\0"
+ "octal value is greater than \\377 in 8-bit non-UTF-8 mode\0"
+ "internal error: overran compiling workspace\0"
+ "internal error: previously-checked referenced subpattern not found\0"
+ "DEFINE group contains more than one branch\0"
+ /* 55 */
+ "missing opening brace after \\o\0"
+ "internal error: unknown newline setting\0"
+ "\\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain number\0"
+ "(?R (recursive pattern call) must be followed by a closing parenthesis\0"
+ /* "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)\0" */
+ "obsolete error (should not occur)\0" /* Was the above */
+ /* 60 */
+ "(*VERB) not recognized or malformed\0"
+ "group number is too big\0"
+ "subpattern name expected\0"
+ "internal error: parsed pattern overflow\0"
+ "non-octal character in \\o{} (closing brace missing?)\0"
+ /* 65 */
+ "different names for subpatterns of the same number are not allowed\0"
+ "(*MARK) must have an argument\0"
+ "non-hex character in \\x{} (closing brace missing?)\0"
+#ifndef EBCDIC
+ "\\c must be followed by a printable ASCII character\0"
+#else
+ "\\c must be followed by a letter or one of [\\]^_?\0"
+#endif
+ "\\k is not followed by a braced, angle-bracketed, or quoted name\0"
+ /* 70 */
+ "internal error: unknown meta code in check_lookbehinds()\0"
+ "\\N is not supported in a class\0"
+ "callout string is too long\0"
+ "disallowed Unicode code point (>= 0xd800 && <= 0xdfff)\0"
+ "using UTF is disabled by the application\0"
+ /* 75 */
+ "using UCP is disabled by the application\0"
+ "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)\0"
+ "character code point value in \\u.... sequence is too large\0"
+ "digits missing in \\x{} or \\o{} or \\N{U+}\0"
+ "syntax error or number too big in (?(VERSION condition\0"
+ /* 80 */
+ "internal error: unknown opcode in auto_possessify()\0"
+ "missing terminating delimiter for callout with string argument\0"
+ "unrecognized string delimiter follows (?C\0"
+ "using \\C is disabled by the application\0"
+ "(?| and/or (?J: or (?x: parentheses are too deeply nested\0"
+ /* 85 */
+ "using \\C is disabled in this PCRE2 library\0"
+ "regular expression is too complicated\0"
+ "lookbehind assertion is too long\0"
+ "pattern string is longer than the limit set by the application\0"
+ "internal error: unknown code in parsed pattern\0"
+ /* 90 */
+ "internal error: bad code value in parsed_skip()\0"
+ "PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES is not allowed in UTF-16 mode\0"
+ "invalid option bits with PCRE2_LITERAL\0"
+ "\\N{U+dddd} is supported only in Unicode (UTF) mode\0"
+ "invalid hyphen in option setting\0"
+ ;
+
+/* Match-time and UTF error texts are in the same format. */
+
+static const unsigned char match_error_texts[] =
+ "no error\0"
+ "no match\0"
+ "partial match\0"
+ "UTF-8 error: 1 byte missing at end\0"
+ "UTF-8 error: 2 bytes missing at end\0"
+ /* 5 */
+ "UTF-8 error: 3 bytes missing at end\0"
+ "UTF-8 error: 4 bytes missing at end\0"
+ "UTF-8 error: 5 bytes missing at end\0"
+ "UTF-8 error: byte 2 top bits not 0x80\0"
+ "UTF-8 error: byte 3 top bits not 0x80\0"
+ /* 10 */
+ "UTF-8 error: byte 4 top bits not 0x80\0"
+ "UTF-8 error: byte 5 top bits not 0x80\0"
+ "UTF-8 error: byte 6 top bits not 0x80\0"
+ "UTF-8 error: 5-byte character is not allowed (RFC 3629)\0"
+ "UTF-8 error: 6-byte character is not allowed (RFC 3629)\0"
+ /* 15 */
+ "UTF-8 error: code points greater than 0x10ffff are not defined\0"
+ "UTF-8 error: code points 0xd800-0xdfff are not defined\0"
+ "UTF-8 error: overlong 2-byte sequence\0"
+ "UTF-8 error: overlong 3-byte sequence\0"
+ "UTF-8 error: overlong 4-byte sequence\0"
+ /* 20 */
+ "UTF-8 error: overlong 5-byte sequence\0"
+ "UTF-8 error: overlong 6-byte sequence\0"
+ "UTF-8 error: isolated byte with 0x80 bit set\0"
+ "UTF-8 error: illegal byte (0xfe or 0xff)\0"
+ "UTF-16 error: missing low surrogate at end\0"
+ /* 25 */
+ "UTF-16 error: invalid low surrogate\0"
+ "UTF-16 error: isolated low surrogate\0"
+ "UTF-32 error: code points 0xd800-0xdfff are not defined\0"
+ "UTF-32 error: code points greater than 0x10ffff are not defined\0"
+ "bad data value\0"
+ /* 30 */
+ "patterns do not all use the same character tables\0"
+ "magic number missing\0"
+ "pattern compiled in wrong mode: 8/16/32-bit error\0"
+ "bad offset value\0"
+ "bad option value\0"
+ /* 35 */
+ "invalid replacement string\0"
+ "bad offset into UTF string\0"
+ "callout error code\0" /* Never returned by PCRE2 itself */
+ "invalid data in workspace for DFA restart\0"
+ "too much recursion for DFA matching\0"
+ /* 40 */
+ "backreference condition or recursion test is not supported for DFA matching\0"
+ "function is not supported for DFA matching\0"
+ "pattern contains an item that is not supported for DFA matching\0"
+ "workspace size exceeded in DFA matching\0"
+ "internal error - pattern overwritten?\0"
+ /* 45 */
+ "bad JIT option\0"
+ "JIT stack limit reached\0"
+ "match limit exceeded\0"
+ "no more memory\0"
+ "unknown substring\0"
+ /* 50 */
+ "non-unique substring name\0"
+ "NULL argument passed\0"
+ "nested recursion at the same subject position\0"
+ "matching depth limit exceeded\0"
+ "requested value is not available\0"
+ /* 55 */
+ "requested value is not set\0"
+ "offset limit set without PCRE2_USE_OFFSET_LIMIT\0"
+ "bad escape sequence in replacement string\0"
+ "expected closing curly bracket in replacement string\0"
+ "bad substitution in replacement string\0"
+ /* 60 */
+ "match with end before start or start moved backwards is not supported\0"
+ "too many replacements (more than INT_MAX)\0"
+ "bad serialized data\0"
+ "heap limit exceeded\0"
+ "invalid syntax\0"
+ /* 65 */
+ "internal error - duplicate substitution match\0"
+ ;
+
+
+/*************************************************
+* Return error message *
+*************************************************/
+
+/* This function copies an error message into a buffer whose units are of an
+appropriate width. Error numbers are positive for compile-time errors, and
+negative for match-time errors (except for UTF errors), but the numbers are all
+distinct.
+
+Arguments:
+ enumber error number
+ buffer where to put the message (zero terminated)
+ size size of the buffer in code units
+
+Returns: length of message if all is well
+ negative on error
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_get_error_message(int enumber, PCRE2_UCHAR *buffer, PCRE2_SIZE size)
+{
+const unsigned char *message;
+PCRE2_SIZE i;
+int n;
+
+if (size == 0) return PCRE2_ERROR_NOMEMORY;
+
+if (enumber >= COMPILE_ERROR_BASE) /* Compile error */
+ {
+ message = compile_error_texts;
+ n = enumber - COMPILE_ERROR_BASE;
+ }
+else if (enumber < 0) /* Match or UTF error */
+ {
+ message = match_error_texts;
+ n = -enumber;
+ }
+else /* Invalid error number */
+ {
+ message = (unsigned char *)"\0"; /* Empty message list */
+ n = 1;
+ }
+
+for (; n > 0; n--)
+ {
+ while (*message++ != CHAR_NUL) {};
+ if (*message == CHAR_NUL) return PCRE2_ERROR_BADDATA;
+ }
+
+for (i = 0; *message != 0; i++)
+ {
+ if (i >= size - 1)
+ {
+ buffer[i] = 0; /* Terminate partial message */
+ return PCRE2_ERROR_NOMEMORY;
+ }
+ buffer[i] = *message++;
+ }
+
+buffer[i] = 0;
+return (int)i;
+}
+
+/* End of pcre2_error.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_extuni.c b/test/monniaux/pcre2-10.32/pcre2_extuni.c
new file mode 100644
index 00000000..237211ab
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_extuni.c
@@ -0,0 +1,148 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains an internal function that is used to match a Unicode
+extended grapheme sequence. It is used by both pcre2_match() and
+pcre2_def_match(). However, it is called only when Unicode support is being
+compiled. Nevertheless, we provide a dummy function when there is no Unicode
+support, because some compilers do not like functionless source files. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+
+/* Dummy function */
+
+#ifndef SUPPORT_UNICODE
+PCRE2_SPTR
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+ PCRE2_SPTR end_subject, BOOL utf, int *xcount)
+{
+(void)c;
+(void)eptr;
+(void)start_subject;
+(void)end_subject;
+(void)utf;
+(void)xcount;
+return NULL;
+}
+#else
+
+
+/*************************************************
+* Match an extended grapheme sequence *
+*************************************************/
+
+/*
+Arguments:
+ c the first character
+ eptr pointer to next character
+ start_subject pointer to start of subject
+ end_subject pointer to end of subject
+ utf TRUE if in UTF mode
+ xcount pointer to count of additional characters,
+ or NULL if count not needed
+
+Returns: pointer after the end of the sequence
+*/
+
+PCRE2_SPTR
+PRIV(extuni)(uint32_t c, PCRE2_SPTR eptr, PCRE2_SPTR start_subject,
+ PCRE2_SPTR end_subject, BOOL utf, int *xcount)
+{
+int lgb = UCD_GRAPHBREAK(c);
+
+while (eptr < end_subject)
+ {
+ int rgb;
+ int len = 1;
+ if (!utf) c = *eptr; else { GETCHARLEN(c, eptr, len); }
+ rgb = UCD_GRAPHBREAK(c);
+ if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+
+ /* Not breaking between Regional Indicators is allowed only if there
+ are an even number of preceding RIs. */
+
+ if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+ {
+ int ricount = 0;
+ PCRE2_SPTR bptr = eptr - 1;
+ if (utf) BACKCHAR(bptr);
+
+ /* bptr is pointing to the left-hand character */
+
+ while (bptr > start_subject)
+ {
+ bptr--;
+ if (utf)
+ {
+ BACKCHAR(bptr);
+ GETCHAR(c, bptr);
+ }
+ else
+ c = *bptr;
+ if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break;
+ ricount++;
+ }
+ if ((ricount & 1) != 0) break; /* Grapheme break required */
+ }
+
+ /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+ allows any number of them before a following Extended_Pictographic. */
+
+ if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+ lgb != ucp_gbExtended_Pictographic)
+ lgb = rgb;
+
+ eptr += len;
+ if (xcount != NULL) *xcount += 1;
+ }
+
+return eptr;
+}
+
+#endif /* SUPPORT_UNICODE */
+
+/* End of pcre2_extuni.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_find_bracket.c b/test/monniaux/pcre2-10.32/pcre2_find_bracket.c
new file mode 100644
index 00000000..70baa139
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_find_bracket.c
@@ -0,0 +1,219 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a single function that scans through a compiled pattern
+until it finds a capturing bracket with the given number, or, if the number is
+negative, an instance of OP_REVERSE for a lookbehind. The function is called
+from pcre2_compile.c and also from pcre2_study.c when finding the minimum
+matching length. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Scan compiled regex for specific bracket *
+*************************************************/
+
+/*
+Arguments:
+ code points to start of expression
+ utf TRUE in UTF mode
+ number the required bracket number or negative to find a lookbehind
+
+Returns: pointer to the opcode for the bracket, or NULL if not found
+*/
+
+PCRE2_SPTR
+PRIV(find_bracket)(PCRE2_SPTR code, BOOL utf, int number)
+{
+for (;;)
+ {
+ PCRE2_UCHAR c = *code;
+
+ if (c == OP_END) return NULL;
+
+ /* XCLASS is used for classes that cannot be represented just by a bit map.
+ This includes negated single high-valued characters. CALLOUT_STR is used for
+ callouts with string arguments. In both cases the length in the table is
+ zero; the actual length is stored in the compiled code. */
+
+ if (c == OP_XCLASS) code += GET(code, 1);
+ else if (c == OP_CALLOUT_STR) code += GET(code, 1 + 2*LINK_SIZE);
+
+ /* Handle lookbehind */
+
+ else if (c == OP_REVERSE)
+ {
+ if (number < 0) return (PCRE2_UCHAR *)code;
+ code += PRIV(OP_lengths)[c];
+ }
+
+ /* Handle capturing bracket */
+
+ else if (c == OP_CBRA || c == OP_SCBRA ||
+ c == OP_CBRAPOS || c == OP_SCBRAPOS)
+ {
+ int n = (int)GET2(code, 1+LINK_SIZE);
+ if (n == number) return (PCRE2_UCHAR *)code;
+ code += PRIV(OP_lengths)[c];
+ }
+
+ /* Otherwise, we can get the item's length from the table, except that for
+ repeated character types, we have to test for \p and \P, which have an extra
+ two bytes of parameters, and for MARK/PRUNE/SKIP/THEN with an argument, we
+ must add in its length. */
+
+ else
+ {
+ switch(c)
+ {
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP) code += 2;
+ break;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSUPTO:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ code += 2;
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ code += code[1];
+ break;
+ }
+
+ /* Add in the fixed length from the table */
+
+ code += PRIV(OP_lengths)[c];
+
+ /* In UTF-8 and UTF-16 modes, opcodes that are followed by a character may be
+ followed by a multi-byte character. The length in the table is a minimum, so
+ we have to arrange to skip the extra bytes. */
+
+#ifdef MAYBE_UTF_MULTI
+ if (utf) switch(c)
+ {
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ case OP_UPTO:
+ case OP_UPTOI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ case OP_STAR:
+ case OP_STARI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
+ break;
+ }
+#else
+ (void)(utf); /* Keep compiler happy by referencing function argument */
+#endif /* MAYBE_UTF_MULTI */
+ }
+ }
+}
+
+/* End of pcre2_find_bracket.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_internal.h b/test/monniaux/pcre2-10.32/pcre2_internal.h
new file mode 100644
index 00000000..8750f2f1
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_internal.h
@@ -0,0 +1,1945 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE2 is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef PCRE2_INTERNAL_H_IDEMPOTENT_GUARD
+#define PCRE2_INTERNAL_H_IDEMPOTENT_GUARD
+
+/* We do not support both EBCDIC and Unicode at the same time. The "configure"
+script prevents both being selected, but not everybody uses "configure". EBCDIC
+is only supported for the 8-bit library, but the check for this has to be later
+in this file, because the first part is not width-dependent, and is included by
+pcre2test.c with CODE_UNIT_WIDTH == 0. */
+
+#if defined EBCDIC && defined SUPPORT_UNICODE
+#error The use of both EBCDIC and SUPPORT_UNICODE is not supported.
+#endif
+
+/* Standard C headers */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Macros to make boolean values more obvious. The #ifndef is to pacify
+compiler warnings in environments where these macros are defined elsewhere.
+Unfortunately, there is no way to do the same for the typedef. */
+
+typedef int BOOL;
+#ifndef FALSE
+#define FALSE 0
+#define TRUE 1
+#endif
+
+/* Valgrind (memcheck) support */
+
+#ifdef SUPPORT_VALGRIND
+#include <valgrind/memcheck.h>
+#endif
+
+/* Older versions of MSVC lack snprintf(). This define allows for
+warning/error-free compilation and testing with MSVC compilers back to at least
+MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
+/* When compiling a DLL for Windows, the exported symbols have to be declared
+using some MS magic. I found some useful information on this web page:
+http://msdn2.microsoft.com/en-us/library/y4h7bcy6(VS.80).aspx. According to the
+information there, using __declspec(dllexport) without "extern" we have a
+definition; with "extern" we have a declaration. The settings here override the
+setting in pcre2.h (which is included below); it defines only PCRE2_EXP_DECL,
+which is all that is needed for applications (they just import the symbols). We
+use:
+
+ PCRE2_EXP_DECL for declarations
+ PCRE2_EXP_DEFN for definitions
+
+The reason for wrapping this in #ifndef PCRE2_EXP_DECL is so that pcre2test,
+which is an application, but needs to import this file in order to "peek" at
+internals, can #include pcre2.h first to get an application's-eye view.
+
+In principle, people compiling for non-Windows, non-Unix-like (i.e. uncommon,
+special-purpose environments) might want to stick other stuff in front of
+exported symbols. That's why, in the non-Windows case, we set PCRE2_EXP_DEFN
+only if it is not already set. */
+
+#ifndef PCRE2_EXP_DECL
+# ifdef _WIN32
+# ifndef PCRE2_STATIC
+# define PCRE2_EXP_DECL extern __declspec(dllexport)
+# define PCRE2_EXP_DEFN __declspec(dllexport)
+# else
+# define PCRE2_EXP_DECL extern
+# define PCRE2_EXP_DEFN
+# endif
+# else
+# ifdef __cplusplus
+# define PCRE2_EXP_DECL extern "C"
+# else
+# define PCRE2_EXP_DECL extern
+# endif
+# ifndef PCRE2_EXP_DEFN
+# define PCRE2_EXP_DEFN PCRE2_EXP_DECL
+# endif
+# endif
+#endif
+
+/* Include the public PCRE2 header and the definitions of UCP character
+property values. This must follow the setting of PCRE2_EXP_DECL above. */
+
+#include "pcre2.h"
+#include "pcre2_ucp.h"
+
+/* When PCRE2 is compiled as a C++ library, the subject pointer can be replaced
+with a custom type. This makes it possible, for example, to allow pcre2_match()
+to process subject strings that are discontinuous by using a smart pointer
+class. It must always be possible to inspect all of the subject string in
+pcre2_match() because of the way it backtracks. */
+
+/* WARNING: This is as yet untested for PCRE2. */
+
+#ifdef CUSTOM_SUBJECT_PTR
+#undef PCRE2_SPTR
+#define PCRE2_SPTR CUSTOM_SUBJECT_PTR
+#endif
+
+/* When checking for integer overflow in pcre2_compile(), we need to handle
+large integers. If a 64-bit integer type is available, we can use that.
+Otherwise we have to cast to double, which of course requires floating point
+arithmetic. Handle this by defining a macro for the appropriate type. If
+stdint.h is available, include it; it may define INT64_MAX. Systems that do not
+have stdint.h (e.g. Solaris) may have inttypes.h. The macro int64_t may be set
+by "configure". */
+
+#if defined HAVE_STDINT_H
+#include <stdint.h>
+#elif defined HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#if defined INT64_MAX || defined int64_t
+#define INT64_OR_DOUBLE int64_t
+#else
+#define INT64_OR_DOUBLE double
+#endif
+
+/* External (in the C sense) functions and tables that are private to the
+libraries are always referenced using the PRIV macro. This makes it possible
+for pcre2test.c to include some of the source files from the libraries using a
+different PRIV definition to avoid name clashes. It also makes it clear in the
+code that a non-static object is being referenced. */
+
+#ifndef PRIV
+#define PRIV(name) _pcre2_##name
+#endif
+
+/* When compiling for use with the Virtual Pascal compiler, these functions
+need to have their names changed. PCRE2 must be compiled with the -DVPCOMPAT
+option on the command line. */
+
+#ifdef VPCOMPAT
+#define strlen(s) _strlen(s)
+#define strncmp(s1,s2,m) _strncmp(s1,s2,m)
+#define memcmp(s,c,n) _memcmp(s,c,n)
+#define memcpy(d,s,n) _memcpy(d,s,n)
+#define memmove(d,s,n) _memmove(d,s,n)
+#define memset(s,c,n) _memset(s,c,n)
+#else /* VPCOMPAT */
+
+/* Otherwise, to cope with SunOS4 and other systems that lack memmove(), define
+a macro that calls an emulating function. */
+
+#ifndef HAVE_MEMMOVE
+#undef memmove /* Some systems may have a macro */
+#define memmove(a, b, c) PRIV(memmove)(a, b, c)
+#endif /* not HAVE_MEMMOVE */
+#endif /* not VPCOMPAT */
+
+/* This is an unsigned int value that no UTF character can ever have, as
+Unicode doesn't go beyond 0x0010ffff. */
+
+#define NOTACHAR 0xffffffff
+
+/* This is the largest valid UTF/Unicode code point. */
+
+#define MAX_UTF_CODE_POINT 0x10ffff
+
+/* Compile-time positive error numbers (all except UTF errors, which are
+negative) start at this value. It should probably never be changed, in case
+some application is checking for specific numbers. There is a copy of this
+#define in pcre2posix.c (which now no longer includes this file). Ideally, a
+way of having a single definition should be found, but as the number is
+unlikely to change, this is not a pressing issue. The original reason for
+having a base other than 0 was to keep the absolute values of compile-time and
+run-time error numbers numerically different, but in the event the code does
+not rely on this. */
+
+#define COMPILE_ERROR_BASE 100
+
+/* The initial frames vector for remembering backtracking points in
+pcre2_match() is allocated on the system stack, of this size (bytes). The size
+must be a multiple of sizeof(PCRE2_SPTR) in all environments, so making it a
+multiple of 8 is best. Typical frame sizes are a few hundred bytes (it depends
+on the number of capturing parentheses) so 20KiB handles quite a few frames. A
+larger vector on the heap is obtained for patterns that need more frames. The
+maximum size of this can be limited. */
+
+#define START_FRAMES_SIZE 20480
+
+/* Similarly, for DFA matching, an initial internal workspace vector is
+allocated on the stack. */
+
+#define DFA_START_RWS_SIZE 30720
+
+/* Define the default BSR convention. */
+
+#ifdef BSR_ANYCRLF
+#define BSR_DEFAULT PCRE2_BSR_ANYCRLF
+#else
+#define BSR_DEFAULT PCRE2_BSR_UNICODE
+#endif
+
+
+/* ---------------- Basic UTF-8 macros ---------------- */
+
+/* These UTF-8 macros are always defined because they are used in pcre2test for
+handling wide characters in 16-bit and 32-bit modes, even if an 8-bit library
+is not supported. */
+
+/* Tests whether a UTF-8 code point needs extra bytes to decode. */
+
+#define HASUTF8EXTRALEN(c) ((c) >= 0xc0)
+
+/* The following macros were originally written in the form of loops that used
+data from the tables whose names start with PRIV(utf8_table). They were
+rewritten by a user so as not to use loops, because in some environments this
+gives a significant performance advantage, and it seems never to do any harm.
+*/
+
+/* Base macro to pick up the remaining bytes of a UTF-8 character, not
+advancing the pointer. */
+
+#define GETUTF8(c, eptr) \
+ { \
+ if ((c & 0x20u) == 0) \
+ c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \
+ else if ((c & 0x10u) == 0) \
+ c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+ else if ((c & 0x08u) == 0) \
+ c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \
+ ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \
+ else if ((c & 0x04u) == 0) \
+ c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \
+ ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \
+ (eptr[4] & 0x3fu); \
+ else \
+ c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \
+ ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \
+ ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \
+ }
+
+/* Base macro to pick up the remaining bytes of a UTF-8 character, advancing
+the pointer. */
+
+#define GETUTF8INC(c, eptr) \
+ { \
+ if ((c & 0x20u) == 0) \
+ c = ((c & 0x1fu) << 6) | (*eptr++ & 0x3fu); \
+ else if ((c & 0x10u) == 0) \
+ { \
+ c = ((c & 0x0fu) << 12) | ((*eptr & 0x3fu) << 6) | (eptr[1] & 0x3fu); \
+ eptr += 2; \
+ } \
+ else if ((c & 0x08u) == 0) \
+ { \
+ c = ((c & 0x07u) << 18) | ((*eptr & 0x3fu) << 12) | \
+ ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+ eptr += 3; \
+ } \
+ else if ((c & 0x04u) == 0) \
+ { \
+ c = ((c & 0x03u) << 24) | ((*eptr & 0x3fu) << 18) | \
+ ((eptr[1] & 0x3fu) << 12) | ((eptr[2] & 0x3fu) << 6) | \
+ (eptr[3] & 0x3fu); \
+ eptr += 4; \
+ } \
+ else \
+ { \
+ c = ((c & 0x01u) << 30) | ((*eptr & 0x3fu) << 24) | \
+ ((eptr[1] & 0x3fu) << 18) | ((eptr[2] & 0x3fu) << 12) | \
+ ((eptr[3] & 0x3fu) << 6) | (eptr[4] & 0x3fu); \
+ eptr += 5; \
+ } \
+ }
+
+/* Base macro to pick up the remaining bytes of a UTF-8 character, not
+advancing the pointer, incrementing the length. */
+
+#define GETUTF8LEN(c, eptr, len) \
+ { \
+ if ((c & 0x20u) == 0) \
+ { \
+ c = ((c & 0x1fu) << 6) | (eptr[1] & 0x3fu); \
+ len++; \
+ } \
+ else if ((c & 0x10u) == 0) \
+ { \
+ c = ((c & 0x0fu) << 12) | ((eptr[1] & 0x3fu) << 6) | (eptr[2] & 0x3fu); \
+ len += 2; \
+ } \
+ else if ((c & 0x08u) == 0) \
+ {\
+ c = ((c & 0x07u) << 18) | ((eptr[1] & 0x3fu) << 12) | \
+ ((eptr[2] & 0x3fu) << 6) | (eptr[3] & 0x3fu); \
+ len += 3; \
+ } \
+ else if ((c & 0x04u) == 0) \
+ { \
+ c = ((c & 0x03u) << 24) | ((eptr[1] & 0x3fu) << 18) | \
+ ((eptr[2] & 0x3fu) << 12) | ((eptr[3] & 0x3fu) << 6) | \
+ (eptr[4] & 0x3fu); \
+ len += 4; \
+ } \
+ else \
+ {\
+ c = ((c & 0x01u) << 30) | ((eptr[1] & 0x3fu) << 24) | \
+ ((eptr[2] & 0x3fu) << 18) | ((eptr[3] & 0x3fu) << 12) | \
+ ((eptr[4] & 0x3fu) << 6) | (eptr[5] & 0x3fu); \
+ len += 5; \
+ } \
+ }
+
+/* --------------- Whitespace macros ---------------- */
+
+/* Tests for Unicode horizontal and vertical whitespace characters must check a
+number of different values. Using a switch statement for this generates the
+fastest code (no loop, no memory access), and there are several places in the
+interpreter code where this happens. In order to ensure that all the case lists
+remain in step, we use macros so that there is only one place where the lists
+are defined.
+
+These values are also required as lists in pcre2_compile.c when processing \h,
+\H, \v and \V in a character class. The lists are defined in pcre2_tables.c,
+but macros that define the values are here so that all the definitions are
+together. The lists must be in ascending character order, terminated by
+NOTACHAR (which is 0xffffffff).
+
+Any changes should ensure that the various macros are kept in step with each
+other. NOTE: The values also appear in pcre2_jit_compile.c. */
+
+/* -------------- ASCII/Unicode environments -------------- */
+
+#ifndef EBCDIC
+
+/* Character U+180E (Mongolian Vowel Separator) is not included in the list of
+spaces in the Unicode file PropList.txt, and Perl does not recognize it as a
+space. However, in many other sources it is listed as a space and has been in
+PCRE (both APIs) for a long time. */
+
+#define HSPACE_LIST \
+ CHAR_HT, CHAR_SPACE, CHAR_NBSP, \
+ 0x1680, 0x180e, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, \
+ 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202f, 0x205f, 0x3000, \
+ NOTACHAR
+
+#define HSPACE_MULTIBYTE_CASES \
+ case 0x1680: /* OGHAM SPACE MARK */ \
+ case 0x180e: /* MONGOLIAN VOWEL SEPARATOR */ \
+ case 0x2000: /* EN QUAD */ \
+ case 0x2001: /* EM QUAD */ \
+ case 0x2002: /* EN SPACE */ \
+ case 0x2003: /* EM SPACE */ \
+ case 0x2004: /* THREE-PER-EM SPACE */ \
+ case 0x2005: /* FOUR-PER-EM SPACE */ \
+ case 0x2006: /* SIX-PER-EM SPACE */ \
+ case 0x2007: /* FIGURE SPACE */ \
+ case 0x2008: /* PUNCTUATION SPACE */ \
+ case 0x2009: /* THIN SPACE */ \
+ case 0x200A: /* HAIR SPACE */ \
+ case 0x202f: /* NARROW NO-BREAK SPACE */ \
+ case 0x205f: /* MEDIUM MATHEMATICAL SPACE */ \
+ case 0x3000 /* IDEOGRAPHIC SPACE */
+
+#define HSPACE_BYTE_CASES \
+ case CHAR_HT: \
+ case CHAR_SPACE: \
+ case CHAR_NBSP
+
+#define HSPACE_CASES \
+ HSPACE_BYTE_CASES: \
+ HSPACE_MULTIBYTE_CASES
+
+#define VSPACE_LIST \
+ CHAR_LF, CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, 0x2028, 0x2029, NOTACHAR
+
+#define VSPACE_MULTIBYTE_CASES \
+ case 0x2028: /* LINE SEPARATOR */ \
+ case 0x2029 /* PARAGRAPH SEPARATOR */
+
+#define VSPACE_BYTE_CASES \
+ case CHAR_LF: \
+ case CHAR_VT: \
+ case CHAR_FF: \
+ case CHAR_CR: \
+ case CHAR_NEL
+
+#define VSPACE_CASES \
+ VSPACE_BYTE_CASES: \
+ VSPACE_MULTIBYTE_CASES
+
+/* -------------- EBCDIC environments -------------- */
+
+#else
+#define HSPACE_LIST CHAR_HT, CHAR_SPACE, CHAR_NBSP, NOTACHAR
+
+#define HSPACE_BYTE_CASES \
+ case CHAR_HT: \
+ case CHAR_SPACE: \
+ case CHAR_NBSP
+
+#define HSPACE_CASES HSPACE_BYTE_CASES
+
+#ifdef EBCDIC_NL25
+#define VSPACE_LIST \
+ CHAR_VT, CHAR_FF, CHAR_CR, CHAR_NEL, CHAR_LF, NOTACHAR
+#else
+#define VSPACE_LIST \
+ CHAR_VT, CHAR_FF, CHAR_CR, CHAR_LF, CHAR_NEL, NOTACHAR
+#endif
+
+#define VSPACE_BYTE_CASES \
+ case CHAR_LF: \
+ case CHAR_VT: \
+ case CHAR_FF: \
+ case CHAR_CR: \
+ case CHAR_NEL
+
+#define VSPACE_CASES VSPACE_BYTE_CASES
+#endif /* EBCDIC */
+
+/* -------------- End of whitespace macros -------------- */
+
+
+/* PCRE2 is able to support several different kinds of newline (CR, LF, CRLF,
+"any" and "anycrlf" at present). The following macros are used to package up
+testing for newlines. NLBLOCK, PSSTART, and PSEND are defined in the various
+modules to indicate in which datablock the parameters exist, and what the
+start/end of string field names are. */
+
+#define NLTYPE_FIXED 0 /* Newline is a fixed length string */
+#define NLTYPE_ANY 1 /* Newline is any Unicode line ending */
+#define NLTYPE_ANYCRLF 2 /* Newline is CR, LF, or CRLF */
+
+/* This macro checks for a newline at the given position */
+
+#define IS_NEWLINE(p) \
+ ((NLBLOCK->nltype != NLTYPE_FIXED)? \
+ ((p) < NLBLOCK->PSEND && \
+ PRIV(is_newline)((p), NLBLOCK->nltype, NLBLOCK->PSEND, \
+ &(NLBLOCK->nllen), utf)) \
+ : \
+ ((p) <= NLBLOCK->PSEND - NLBLOCK->nllen && \
+ UCHAR21TEST(p) == NLBLOCK->nl[0] && \
+ (NLBLOCK->nllen == 1 || UCHAR21TEST(p+1) == NLBLOCK->nl[1]) \
+ ) \
+ )
+
+/* This macro checks for a newline immediately preceding the given position */
+
+#define WAS_NEWLINE(p) \
+ ((NLBLOCK->nltype != NLTYPE_FIXED)? \
+ ((p) > NLBLOCK->PSSTART && \
+ PRIV(was_newline)((p), NLBLOCK->nltype, NLBLOCK->PSSTART, \
+ &(NLBLOCK->nllen), utf)) \
+ : \
+ ((p) >= NLBLOCK->PSSTART + NLBLOCK->nllen && \
+ UCHAR21TEST(p - NLBLOCK->nllen) == NLBLOCK->nl[0] && \
+ (NLBLOCK->nllen == 1 || UCHAR21TEST(p - NLBLOCK->nllen + 1) == NLBLOCK->nl[1]) \
+ ) \
+ )
+
+/* Private flags containing information about the compiled pattern. The first
+three must not be changed, because whichever is set is actually the number of
+bytes in a code unit in that mode. */
+
+#define PCRE2_MODE8 0x00000001 /* compiled in 8 bit mode */
+#define PCRE2_MODE16 0x00000002 /* compiled in 16 bit mode */
+#define PCRE2_MODE32 0x00000004 /* compiled in 32 bit mode */
+#define PCRE2_FIRSTSET 0x00000010 /* first_code unit is set */
+#define PCRE2_FIRSTCASELESS 0x00000020 /* caseless first code unit */
+#define PCRE2_FIRSTMAPSET 0x00000040 /* bitmap of first code units is set */
+#define PCRE2_LASTSET 0x00000080 /* last code unit is set */
+#define PCRE2_LASTCASELESS 0x00000100 /* caseless last code unit */
+#define PCRE2_STARTLINE 0x00000200 /* start after \n for multiline */
+#define PCRE2_JCHANGED 0x00000400 /* j option used in pattern */
+#define PCRE2_HASCRORLF 0x00000800 /* explicit \r or \n in pattern */
+#define PCRE2_HASTHEN 0x00001000 /* pattern contains (*THEN) */
+#define PCRE2_MATCH_EMPTY 0x00002000 /* pattern can match empty string */
+#define PCRE2_BSR_SET 0x00004000 /* BSR was set in the pattern */
+#define PCRE2_NL_SET 0x00008000 /* newline was set in the pattern */
+#define PCRE2_NOTEMPTY_SET 0x00010000 /* (*NOTEMPTY) used ) keep */
+#define PCRE2_NE_ATST_SET 0x00020000 /* (*NOTEMPTY_ATSTART) used) together */
+#define PCRE2_DEREF_TABLES 0x00040000 /* release character tables */
+#define PCRE2_NOJIT 0x00080000 /* (*NOJIT) used */
+#define PCRE2_HASBKPORX 0x00100000 /* contains \P, \p, or \X */
+#define PCRE2_DUPCAPUSED 0x00200000 /* contains (?| */
+#define PCRE2_HASBKC 0x00400000 /* contains \C */
+
+#define PCRE2_MODE_MASK (PCRE2_MODE8 | PCRE2_MODE16 | PCRE2_MODE32)
+
+/* Values for the matchedby field in a match data block. */
+
+enum { PCRE2_MATCHEDBY_INTERPRETER, /* pcre2_match() */
+ PCRE2_MATCHEDBY_DFA_INTERPRETER, /* pcre2_dfa_match() */
+ PCRE2_MATCHEDBY_JIT }; /* pcre2_jit_match() */
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define MAGIC_NUMBER 0x50435245UL /* 'PCRE' */
+
+/* The maximum remaining length of subject we are prepared to search for a
+req_unit match. In 8-bit mode, memchr() is used and is much faster than the
+search loop that has to be used in 16-bit and 32-bit modes. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define REQ_CU_MAX 2000
+#else
+#define REQ_CU_MAX 1000
+#endif
+
+/* Offsets for the bitmap tables in the cbits set of tables. Each table
+contains a set of bits for a class map. Some classes are built by combining
+these tables. */
+
+#define cbit_space 0 /* [:space:] or \s */
+#define cbit_xdigit 32 /* [:xdigit:] */
+#define cbit_digit 64 /* [:digit:] or \d */
+#define cbit_upper 96 /* [:upper:] */
+#define cbit_lower 128 /* [:lower:] */
+#define cbit_word 160 /* [:word:] or \w */
+#define cbit_graph 192 /* [:graph:] */
+#define cbit_print 224 /* [:print:] */
+#define cbit_punct 256 /* [:punct:] */
+#define cbit_cntrl 288 /* [:cntrl:] */
+#define cbit_length 320 /* Length of the cbits table */
+
+/* Bit definitions for entries in the ctypes table. Do not change these values
+without checking pcre2_jit_compile.c, which has an assertion to ensure that
+ctype_word has the value 16. */
+
+#define ctype_space 0x01
+#define ctype_letter 0x02
+#define ctype_digit 0x04
+#define ctype_xdigit 0x08 /* not actually used any more */
+#define ctype_word 0x10 /* alphanumeric or '_' */
+
+/* Offsets of the various tables from the base tables pointer, and
+total length of the tables. */
+
+#define lcc_offset 0 /* Lower case */
+#define fcc_offset 256 /* Flip case */
+#define cbits_offset 512 /* Character classes */
+#define ctypes_offset (cbits_offset + cbit_length) /* Character types */
+#define tables_length (ctypes_offset + 256)
+
+
+/* -------------------- Character and string names ------------------------ */
+
+/* If PCRE2 is to support UTF-8 on EBCDIC platforms, we cannot use normal
+character constants like '*' because the compiler would emit their EBCDIC code,
+which is different from their ASCII/UTF-8 code. Instead we define macros for
+the characters so that they always use the ASCII/UTF-8 code when UTF-8 support
+is enabled. When UTF-8 support is not enabled, the definitions use character
+literals. Both character and string versions of each character are needed, and
+there are some longer strings as well.
+
+This means that, on EBCDIC platforms, the PCRE2 library can handle either
+EBCDIC, or UTF-8, but not both. To support both in the same compiled library
+would need different lookups depending on whether PCRE2_UTF was set or not.
+This would make it impossible to use characters in switch/case statements,
+which would reduce performance. For a theoretical use (which nobody has asked
+for) in a minority area (EBCDIC platforms), this is not sensible. Any
+application that did need both could compile two versions of the library, using
+macros to give the functions distinct names. */
+
+#ifndef SUPPORT_UNICODE
+
+/* UTF-8 support is not enabled; use the platform-dependent character literals
+so that PCRE2 works in both ASCII and EBCDIC environments, but only in non-UTF
+mode. Newline characters are problematic in EBCDIC. Though it has CR and LF
+characters, a common practice has been to use its NL (0x15) character as the
+line terminator in C-like processing environments. However, sometimes the LF
+(0x25) character is used instead, according to this Unicode document:
+
+http://unicode.org/standard/reports/tr13/tr13-5.html
+
+PCRE2 defaults EBCDIC NL to 0x15, but has a build-time option to select 0x25
+instead. Whichever is *not* chosen is defined as NEL.
+
+In both ASCII and EBCDIC environments, CHAR_NL and CHAR_LF are synonyms for the
+same code point. */
+
+#ifdef EBCDIC
+
+#ifndef EBCDIC_NL25
+#define CHAR_NL '\x15'
+#define CHAR_NEL '\x25'
+#define STR_NL "\x15"
+#define STR_NEL "\x25"
+#else
+#define CHAR_NL '\x25'
+#define CHAR_NEL '\x15'
+#define STR_NL "\x25"
+#define STR_NEL "\x15"
+#endif
+
+#define CHAR_LF CHAR_NL
+#define STR_LF STR_NL
+
+#define CHAR_ESC '\047'
+#define CHAR_DEL '\007'
+#define CHAR_NBSP ((unsigned char)'\x41')
+#define STR_ESC "\047"
+#define STR_DEL "\007"
+
+#else /* Not EBCDIC */
+
+/* In ASCII/Unicode, linefeed is '\n' and we equate this to NL for
+compatibility. NEL is the Unicode newline character; make sure it is
+a positive value. */
+
+#define CHAR_LF '\n'
+#define CHAR_NL CHAR_LF
+#define CHAR_NEL ((unsigned char)'\x85')
+#define CHAR_ESC '\033'
+#define CHAR_DEL '\177'
+#define CHAR_NBSP ((unsigned char)'\xa0')
+
+#define STR_LF "\n"
+#define STR_NL STR_LF
+#define STR_NEL "\x85"
+#define STR_ESC "\033"
+#define STR_DEL "\177"
+
+#endif /* EBCDIC */
+
+/* The remaining definitions work in both environments. */
+
+#define CHAR_NUL '\0'
+#define CHAR_HT '\t'
+#define CHAR_VT '\v'
+#define CHAR_FF '\f'
+#define CHAR_CR '\r'
+#define CHAR_BS '\b'
+#define CHAR_BEL '\a'
+
+#define CHAR_SPACE ' '
+#define CHAR_EXCLAMATION_MARK '!'
+#define CHAR_QUOTATION_MARK '"'
+#define CHAR_NUMBER_SIGN '#'
+#define CHAR_DOLLAR_SIGN '$'
+#define CHAR_PERCENT_SIGN '%'
+#define CHAR_AMPERSAND '&'
+#define CHAR_APOSTROPHE '\''
+#define CHAR_LEFT_PARENTHESIS '('
+#define CHAR_RIGHT_PARENTHESIS ')'
+#define CHAR_ASTERISK '*'
+#define CHAR_PLUS '+'
+#define CHAR_COMMA ','
+#define CHAR_MINUS '-'
+#define CHAR_DOT '.'
+#define CHAR_SLASH '/'
+#define CHAR_0 '0'
+#define CHAR_1 '1'
+#define CHAR_2 '2'
+#define CHAR_3 '3'
+#define CHAR_4 '4'
+#define CHAR_5 '5'
+#define CHAR_6 '6'
+#define CHAR_7 '7'
+#define CHAR_8 '8'
+#define CHAR_9 '9'
+#define CHAR_COLON ':'
+#define CHAR_SEMICOLON ';'
+#define CHAR_LESS_THAN_SIGN '<'
+#define CHAR_EQUALS_SIGN '='
+#define CHAR_GREATER_THAN_SIGN '>'
+#define CHAR_QUESTION_MARK '?'
+#define CHAR_COMMERCIAL_AT '@'
+#define CHAR_A 'A'
+#define CHAR_B 'B'
+#define CHAR_C 'C'
+#define CHAR_D 'D'
+#define CHAR_E 'E'
+#define CHAR_F 'F'
+#define CHAR_G 'G'
+#define CHAR_H 'H'
+#define CHAR_I 'I'
+#define CHAR_J 'J'
+#define CHAR_K 'K'
+#define CHAR_L 'L'
+#define CHAR_M 'M'
+#define CHAR_N 'N'
+#define CHAR_O 'O'
+#define CHAR_P 'P'
+#define CHAR_Q 'Q'
+#define CHAR_R 'R'
+#define CHAR_S 'S'
+#define CHAR_T 'T'
+#define CHAR_U 'U'
+#define CHAR_V 'V'
+#define CHAR_W 'W'
+#define CHAR_X 'X'
+#define CHAR_Y 'Y'
+#define CHAR_Z 'Z'
+#define CHAR_LEFT_SQUARE_BRACKET '['
+#define CHAR_BACKSLASH '\\'
+#define CHAR_RIGHT_SQUARE_BRACKET ']'
+#define CHAR_CIRCUMFLEX_ACCENT '^'
+#define CHAR_UNDERSCORE '_'
+#define CHAR_GRAVE_ACCENT '`'
+#define CHAR_a 'a'
+#define CHAR_b 'b'
+#define CHAR_c 'c'
+#define CHAR_d 'd'
+#define CHAR_e 'e'
+#define CHAR_f 'f'
+#define CHAR_g 'g'
+#define CHAR_h 'h'
+#define CHAR_i 'i'
+#define CHAR_j 'j'
+#define CHAR_k 'k'
+#define CHAR_l 'l'
+#define CHAR_m 'm'
+#define CHAR_n 'n'
+#define CHAR_o 'o'
+#define CHAR_p 'p'
+#define CHAR_q 'q'
+#define CHAR_r 'r'
+#define CHAR_s 's'
+#define CHAR_t 't'
+#define CHAR_u 'u'
+#define CHAR_v 'v'
+#define CHAR_w 'w'
+#define CHAR_x 'x'
+#define CHAR_y 'y'
+#define CHAR_z 'z'
+#define CHAR_LEFT_CURLY_BRACKET '{'
+#define CHAR_VERTICAL_LINE '|'
+#define CHAR_RIGHT_CURLY_BRACKET '}'
+#define CHAR_TILDE '~'
+
+#define STR_HT "\t"
+#define STR_VT "\v"
+#define STR_FF "\f"
+#define STR_CR "\r"
+#define STR_BS "\b"
+#define STR_BEL "\a"
+
+#define STR_SPACE " "
+#define STR_EXCLAMATION_MARK "!"
+#define STR_QUOTATION_MARK "\""
+#define STR_NUMBER_SIGN "#"
+#define STR_DOLLAR_SIGN "$"
+#define STR_PERCENT_SIGN "%"
+#define STR_AMPERSAND "&"
+#define STR_APOSTROPHE "'"
+#define STR_LEFT_PARENTHESIS "("
+#define STR_RIGHT_PARENTHESIS ")"
+#define STR_ASTERISK "*"
+#define STR_PLUS "+"
+#define STR_COMMA ","
+#define STR_MINUS "-"
+#define STR_DOT "."
+#define STR_SLASH "/"
+#define STR_0 "0"
+#define STR_1 "1"
+#define STR_2 "2"
+#define STR_3 "3"
+#define STR_4 "4"
+#define STR_5 "5"
+#define STR_6 "6"
+#define STR_7 "7"
+#define STR_8 "8"
+#define STR_9 "9"
+#define STR_COLON ":"
+#define STR_SEMICOLON ";"
+#define STR_LESS_THAN_SIGN "<"
+#define STR_EQUALS_SIGN "="
+#define STR_GREATER_THAN_SIGN ">"
+#define STR_QUESTION_MARK "?"
+#define STR_COMMERCIAL_AT "@"
+#define STR_A "A"
+#define STR_B "B"
+#define STR_C "C"
+#define STR_D "D"
+#define STR_E "E"
+#define STR_F "F"
+#define STR_G "G"
+#define STR_H "H"
+#define STR_I "I"
+#define STR_J "J"
+#define STR_K "K"
+#define STR_L "L"
+#define STR_M "M"
+#define STR_N "N"
+#define STR_O "O"
+#define STR_P "P"
+#define STR_Q "Q"
+#define STR_R "R"
+#define STR_S "S"
+#define STR_T "T"
+#define STR_U "U"
+#define STR_V "V"
+#define STR_W "W"
+#define STR_X "X"
+#define STR_Y "Y"
+#define STR_Z "Z"
+#define STR_LEFT_SQUARE_BRACKET "["
+#define STR_BACKSLASH "\\"
+#define STR_RIGHT_SQUARE_BRACKET "]"
+#define STR_CIRCUMFLEX_ACCENT "^"
+#define STR_UNDERSCORE "_"
+#define STR_GRAVE_ACCENT "`"
+#define STR_a "a"
+#define STR_b "b"
+#define STR_c "c"
+#define STR_d "d"
+#define STR_e "e"
+#define STR_f "f"
+#define STR_g "g"
+#define STR_h "h"
+#define STR_i "i"
+#define STR_j "j"
+#define STR_k "k"
+#define STR_l "l"
+#define STR_m "m"
+#define STR_n "n"
+#define STR_o "o"
+#define STR_p "p"
+#define STR_q "q"
+#define STR_r "r"
+#define STR_s "s"
+#define STR_t "t"
+#define STR_u "u"
+#define STR_v "v"
+#define STR_w "w"
+#define STR_x "x"
+#define STR_y "y"
+#define STR_z "z"
+#define STR_LEFT_CURLY_BRACKET "{"
+#define STR_VERTICAL_LINE "|"
+#define STR_RIGHT_CURLY_BRACKET "}"
+#define STR_TILDE "~"
+
+#define STRING_ACCEPT0 "ACCEPT\0"
+#define STRING_COMMIT0 "COMMIT\0"
+#define STRING_F0 "F\0"
+#define STRING_FAIL0 "FAIL\0"
+#define STRING_MARK0 "MARK\0"
+#define STRING_PRUNE0 "PRUNE\0"
+#define STRING_SKIP0 "SKIP\0"
+#define STRING_THEN "THEN"
+
+#define STRING_alpha0 "alpha\0"
+#define STRING_lower0 "lower\0"
+#define STRING_upper0 "upper\0"
+#define STRING_alnum0 "alnum\0"
+#define STRING_ascii0 "ascii\0"
+#define STRING_blank0 "blank\0"
+#define STRING_cntrl0 "cntrl\0"
+#define STRING_digit0 "digit\0"
+#define STRING_graph0 "graph\0"
+#define STRING_print0 "print\0"
+#define STRING_punct0 "punct\0"
+#define STRING_space0 "space\0"
+#define STRING_word0 "word\0"
+#define STRING_xdigit "xdigit"
+
+#define STRING_DEFINE "DEFINE"
+#define STRING_VERSION "VERSION"
+#define STRING_WEIRD_STARTWORD "[:<:]]"
+#define STRING_WEIRD_ENDWORD "[:>:]]"
+
+#define STRING_CR_RIGHTPAR "CR)"
+#define STRING_LF_RIGHTPAR "LF)"
+#define STRING_CRLF_RIGHTPAR "CRLF)"
+#define STRING_ANY_RIGHTPAR "ANY)"
+#define STRING_ANYCRLF_RIGHTPAR "ANYCRLF)"
+#define STRING_NUL_RIGHTPAR "NUL)"
+#define STRING_BSR_ANYCRLF_RIGHTPAR "BSR_ANYCRLF)"
+#define STRING_BSR_UNICODE_RIGHTPAR "BSR_UNICODE)"
+#define STRING_UTF8_RIGHTPAR "UTF8)"
+#define STRING_UTF16_RIGHTPAR "UTF16)"
+#define STRING_UTF32_RIGHTPAR "UTF32)"
+#define STRING_UTF_RIGHTPAR "UTF)"
+#define STRING_UCP_RIGHTPAR "UCP)"
+#define STRING_NO_AUTO_POSSESS_RIGHTPAR "NO_AUTO_POSSESS)"
+#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR "NO_DOTSTAR_ANCHOR)"
+#define STRING_NO_JIT_RIGHTPAR "NO_JIT)"
+#define STRING_NO_START_OPT_RIGHTPAR "NO_START_OPT)"
+#define STRING_NOTEMPTY_RIGHTPAR "NOTEMPTY)"
+#define STRING_NOTEMPTY_ATSTART_RIGHTPAR "NOTEMPTY_ATSTART)"
+#define STRING_LIMIT_HEAP_EQ "LIMIT_HEAP="
+#define STRING_LIMIT_MATCH_EQ "LIMIT_MATCH="
+#define STRING_LIMIT_DEPTH_EQ "LIMIT_DEPTH="
+#define STRING_LIMIT_RECURSION_EQ "LIMIT_RECURSION="
+#define STRING_MARK "MARK"
+
+#else /* SUPPORT_UNICODE */
+
+/* UTF-8 support is enabled; always use UTF-8 (=ASCII) character codes. This
+works in both modes non-EBCDIC platforms, and on EBCDIC platforms in UTF-8 mode
+only. */
+
+#define CHAR_HT '\011'
+#define CHAR_VT '\013'
+#define CHAR_FF '\014'
+#define CHAR_CR '\015'
+#define CHAR_LF '\012'
+#define CHAR_NL CHAR_LF
+#define CHAR_NEL ((unsigned char)'\x85')
+#define CHAR_BS '\010'
+#define CHAR_BEL '\007'
+#define CHAR_ESC '\033'
+#define CHAR_DEL '\177'
+
+#define CHAR_NUL '\0'
+#define CHAR_SPACE '\040'
+#define CHAR_EXCLAMATION_MARK '\041'
+#define CHAR_QUOTATION_MARK '\042'
+#define CHAR_NUMBER_SIGN '\043'
+#define CHAR_DOLLAR_SIGN '\044'
+#define CHAR_PERCENT_SIGN '\045'
+#define CHAR_AMPERSAND '\046'
+#define CHAR_APOSTROPHE '\047'
+#define CHAR_LEFT_PARENTHESIS '\050'
+#define CHAR_RIGHT_PARENTHESIS '\051'
+#define CHAR_ASTERISK '\052'
+#define CHAR_PLUS '\053'
+#define CHAR_COMMA '\054'
+#define CHAR_MINUS '\055'
+#define CHAR_DOT '\056'
+#define CHAR_SLASH '\057'
+#define CHAR_0 '\060'
+#define CHAR_1 '\061'
+#define CHAR_2 '\062'
+#define CHAR_3 '\063'
+#define CHAR_4 '\064'
+#define CHAR_5 '\065'
+#define CHAR_6 '\066'
+#define CHAR_7 '\067'
+#define CHAR_8 '\070'
+#define CHAR_9 '\071'
+#define CHAR_COLON '\072'
+#define CHAR_SEMICOLON '\073'
+#define CHAR_LESS_THAN_SIGN '\074'
+#define CHAR_EQUALS_SIGN '\075'
+#define CHAR_GREATER_THAN_SIGN '\076'
+#define CHAR_QUESTION_MARK '\077'
+#define CHAR_COMMERCIAL_AT '\100'
+#define CHAR_A '\101'
+#define CHAR_B '\102'
+#define CHAR_C '\103'
+#define CHAR_D '\104'
+#define CHAR_E '\105'
+#define CHAR_F '\106'
+#define CHAR_G '\107'
+#define CHAR_H '\110'
+#define CHAR_I '\111'
+#define CHAR_J '\112'
+#define CHAR_K '\113'
+#define CHAR_L '\114'
+#define CHAR_M '\115'
+#define CHAR_N '\116'
+#define CHAR_O '\117'
+#define CHAR_P '\120'
+#define CHAR_Q '\121'
+#define CHAR_R '\122'
+#define CHAR_S '\123'
+#define CHAR_T '\124'
+#define CHAR_U '\125'
+#define CHAR_V '\126'
+#define CHAR_W '\127'
+#define CHAR_X '\130'
+#define CHAR_Y '\131'
+#define CHAR_Z '\132'
+#define CHAR_LEFT_SQUARE_BRACKET '\133'
+#define CHAR_BACKSLASH '\134'
+#define CHAR_RIGHT_SQUARE_BRACKET '\135'
+#define CHAR_CIRCUMFLEX_ACCENT '\136'
+#define CHAR_UNDERSCORE '\137'
+#define CHAR_GRAVE_ACCENT '\140'
+#define CHAR_a '\141'
+#define CHAR_b '\142'
+#define CHAR_c '\143'
+#define CHAR_d '\144'
+#define CHAR_e '\145'
+#define CHAR_f '\146'
+#define CHAR_g '\147'
+#define CHAR_h '\150'
+#define CHAR_i '\151'
+#define CHAR_j '\152'
+#define CHAR_k '\153'
+#define CHAR_l '\154'
+#define CHAR_m '\155'
+#define CHAR_n '\156'
+#define CHAR_o '\157'
+#define CHAR_p '\160'
+#define CHAR_q '\161'
+#define CHAR_r '\162'
+#define CHAR_s '\163'
+#define CHAR_t '\164'
+#define CHAR_u '\165'
+#define CHAR_v '\166'
+#define CHAR_w '\167'
+#define CHAR_x '\170'
+#define CHAR_y '\171'
+#define CHAR_z '\172'
+#define CHAR_LEFT_CURLY_BRACKET '\173'
+#define CHAR_VERTICAL_LINE '\174'
+#define CHAR_RIGHT_CURLY_BRACKET '\175'
+#define CHAR_TILDE '\176'
+#define CHAR_NBSP ((unsigned char)'\xa0')
+
+#define STR_HT "\011"
+#define STR_VT "\013"
+#define STR_FF "\014"
+#define STR_CR "\015"
+#define STR_NL "\012"
+#define STR_BS "\010"
+#define STR_BEL "\007"
+#define STR_ESC "\033"
+#define STR_DEL "\177"
+
+#define STR_SPACE "\040"
+#define STR_EXCLAMATION_MARK "\041"
+#define STR_QUOTATION_MARK "\042"
+#define STR_NUMBER_SIGN "\043"
+#define STR_DOLLAR_SIGN "\044"
+#define STR_PERCENT_SIGN "\045"
+#define STR_AMPERSAND "\046"
+#define STR_APOSTROPHE "\047"
+#define STR_LEFT_PARENTHESIS "\050"
+#define STR_RIGHT_PARENTHESIS "\051"
+#define STR_ASTERISK "\052"
+#define STR_PLUS "\053"
+#define STR_COMMA "\054"
+#define STR_MINUS "\055"
+#define STR_DOT "\056"
+#define STR_SLASH "\057"
+#define STR_0 "\060"
+#define STR_1 "\061"
+#define STR_2 "\062"
+#define STR_3 "\063"
+#define STR_4 "\064"
+#define STR_5 "\065"
+#define STR_6 "\066"
+#define STR_7 "\067"
+#define STR_8 "\070"
+#define STR_9 "\071"
+#define STR_COLON "\072"
+#define STR_SEMICOLON "\073"
+#define STR_LESS_THAN_SIGN "\074"
+#define STR_EQUALS_SIGN "\075"
+#define STR_GREATER_THAN_SIGN "\076"
+#define STR_QUESTION_MARK "\077"
+#define STR_COMMERCIAL_AT "\100"
+#define STR_A "\101"
+#define STR_B "\102"
+#define STR_C "\103"
+#define STR_D "\104"
+#define STR_E "\105"
+#define STR_F "\106"
+#define STR_G "\107"
+#define STR_H "\110"
+#define STR_I "\111"
+#define STR_J "\112"
+#define STR_K "\113"
+#define STR_L "\114"
+#define STR_M "\115"
+#define STR_N "\116"
+#define STR_O "\117"
+#define STR_P "\120"
+#define STR_Q "\121"
+#define STR_R "\122"
+#define STR_S "\123"
+#define STR_T "\124"
+#define STR_U "\125"
+#define STR_V "\126"
+#define STR_W "\127"
+#define STR_X "\130"
+#define STR_Y "\131"
+#define STR_Z "\132"
+#define STR_LEFT_SQUARE_BRACKET "\133"
+#define STR_BACKSLASH "\134"
+#define STR_RIGHT_SQUARE_BRACKET "\135"
+#define STR_CIRCUMFLEX_ACCENT "\136"
+#define STR_UNDERSCORE "\137"
+#define STR_GRAVE_ACCENT "\140"
+#define STR_a "\141"
+#define STR_b "\142"
+#define STR_c "\143"
+#define STR_d "\144"
+#define STR_e "\145"
+#define STR_f "\146"
+#define STR_g "\147"
+#define STR_h "\150"
+#define STR_i "\151"
+#define STR_j "\152"
+#define STR_k "\153"
+#define STR_l "\154"
+#define STR_m "\155"
+#define STR_n "\156"
+#define STR_o "\157"
+#define STR_p "\160"
+#define STR_q "\161"
+#define STR_r "\162"
+#define STR_s "\163"
+#define STR_t "\164"
+#define STR_u "\165"
+#define STR_v "\166"
+#define STR_w "\167"
+#define STR_x "\170"
+#define STR_y "\171"
+#define STR_z "\172"
+#define STR_LEFT_CURLY_BRACKET "\173"
+#define STR_VERTICAL_LINE "\174"
+#define STR_RIGHT_CURLY_BRACKET "\175"
+#define STR_TILDE "\176"
+
+#define STRING_ACCEPT0 STR_A STR_C STR_C STR_E STR_P STR_T "\0"
+#define STRING_COMMIT0 STR_C STR_O STR_M STR_M STR_I STR_T "\0"
+#define STRING_F0 STR_F "\0"
+#define STRING_FAIL0 STR_F STR_A STR_I STR_L "\0"
+#define STRING_MARK0 STR_M STR_A STR_R STR_K "\0"
+#define STRING_PRUNE0 STR_P STR_R STR_U STR_N STR_E "\0"
+#define STRING_SKIP0 STR_S STR_K STR_I STR_P "\0"
+#define STRING_THEN STR_T STR_H STR_E STR_N
+
+#define STRING_alpha0 STR_a STR_l STR_p STR_h STR_a "\0"
+#define STRING_lower0 STR_l STR_o STR_w STR_e STR_r "\0"
+#define STRING_upper0 STR_u STR_p STR_p STR_e STR_r "\0"
+#define STRING_alnum0 STR_a STR_l STR_n STR_u STR_m "\0"
+#define STRING_ascii0 STR_a STR_s STR_c STR_i STR_i "\0"
+#define STRING_blank0 STR_b STR_l STR_a STR_n STR_k "\0"
+#define STRING_cntrl0 STR_c STR_n STR_t STR_r STR_l "\0"
+#define STRING_digit0 STR_d STR_i STR_g STR_i STR_t "\0"
+#define STRING_graph0 STR_g STR_r STR_a STR_p STR_h "\0"
+#define STRING_print0 STR_p STR_r STR_i STR_n STR_t "\0"
+#define STRING_punct0 STR_p STR_u STR_n STR_c STR_t "\0"
+#define STRING_space0 STR_s STR_p STR_a STR_c STR_e "\0"
+#define STRING_word0 STR_w STR_o STR_r STR_d "\0"
+#define STRING_xdigit STR_x STR_d STR_i STR_g STR_i STR_t
+
+#define STRING_DEFINE STR_D STR_E STR_F STR_I STR_N STR_E
+#define STRING_VERSION STR_V STR_E STR_R STR_S STR_I STR_O STR_N
+#define STRING_WEIRD_STARTWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_LESS_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
+#define STRING_WEIRD_ENDWORD STR_LEFT_SQUARE_BRACKET STR_COLON STR_GREATER_THAN_SIGN STR_COLON STR_RIGHT_SQUARE_BRACKET STR_RIGHT_SQUARE_BRACKET
+
+#define STRING_CR_RIGHTPAR STR_C STR_R STR_RIGHT_PARENTHESIS
+#define STRING_LF_RIGHTPAR STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_CRLF_RIGHTPAR STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_ANY_RIGHTPAR STR_A STR_N STR_Y STR_RIGHT_PARENTHESIS
+#define STRING_ANYCRLF_RIGHTPAR STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_NUL_RIGHTPAR STR_N STR_U STR_L STR_RIGHT_PARENTHESIS
+#define STRING_BSR_ANYCRLF_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_A STR_N STR_Y STR_C STR_R STR_L STR_F STR_RIGHT_PARENTHESIS
+#define STRING_BSR_UNICODE_RIGHTPAR STR_B STR_S STR_R STR_UNDERSCORE STR_U STR_N STR_I STR_C STR_O STR_D STR_E STR_RIGHT_PARENTHESIS
+#define STRING_UTF8_RIGHTPAR STR_U STR_T STR_F STR_8 STR_RIGHT_PARENTHESIS
+#define STRING_UTF16_RIGHTPAR STR_U STR_T STR_F STR_1 STR_6 STR_RIGHT_PARENTHESIS
+#define STRING_UTF32_RIGHTPAR STR_U STR_T STR_F STR_3 STR_2 STR_RIGHT_PARENTHESIS
+#define STRING_UTF_RIGHTPAR STR_U STR_T STR_F STR_RIGHT_PARENTHESIS
+#define STRING_UCP_RIGHTPAR STR_U STR_C STR_P STR_RIGHT_PARENTHESIS
+#define STRING_NO_AUTO_POSSESS_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_A STR_U STR_T STR_O STR_UNDERSCORE STR_P STR_O STR_S STR_S STR_E STR_S STR_S STR_RIGHT_PARENTHESIS
+#define STRING_NO_DOTSTAR_ANCHOR_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_D STR_O STR_T STR_S STR_T STR_A STR_R STR_UNDERSCORE STR_A STR_N STR_C STR_H STR_O STR_R STR_RIGHT_PARENTHESIS
+#define STRING_NO_JIT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_J STR_I STR_T STR_RIGHT_PARENTHESIS
+#define STRING_NO_START_OPT_RIGHTPAR STR_N STR_O STR_UNDERSCORE STR_S STR_T STR_A STR_R STR_T STR_UNDERSCORE STR_O STR_P STR_T STR_RIGHT_PARENTHESIS
+#define STRING_NOTEMPTY_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_RIGHT_PARENTHESIS
+#define STRING_NOTEMPTY_ATSTART_RIGHTPAR STR_N STR_O STR_T STR_E STR_M STR_P STR_T STR_Y STR_UNDERSCORE STR_A STR_T STR_S STR_T STR_A STR_R STR_T STR_RIGHT_PARENTHESIS
+#define STRING_LIMIT_HEAP_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_H STR_E STR_A STR_P STR_EQUALS_SIGN
+#define STRING_LIMIT_MATCH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_M STR_A STR_T STR_C STR_H STR_EQUALS_SIGN
+#define STRING_LIMIT_DEPTH_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_D STR_E STR_P STR_T STR_H STR_EQUALS_SIGN
+#define STRING_LIMIT_RECURSION_EQ STR_L STR_I STR_M STR_I STR_T STR_UNDERSCORE STR_R STR_E STR_C STR_U STR_R STR_S STR_I STR_O STR_N STR_EQUALS_SIGN
+#define STRING_MARK STR_M STR_A STR_R STR_K
+
+#endif /* SUPPORT_UNICODE */
+
+/* -------------------- End of character and string names -------------------*/
+
+/* -------------------- Definitions for compiled patterns -------------------*/
+
+/* Codes for different types of Unicode property */
+
+#define PT_ANY 0 /* Any property - matches all chars */
+#define PT_LAMP 1 /* L& - the union of Lu, Ll, Lt */
+#define PT_GC 2 /* Specified general characteristic (e.g. L) */
+#define PT_PC 3 /* Specified particular characteristic (e.g. Lu) */
+#define PT_SC 4 /* Script (e.g. Han) */
+#define PT_ALNUM 5 /* Alphanumeric - the union of L and N */
+#define PT_SPACE 6 /* Perl space - Z plus 9,10,12,13 */
+#define PT_PXSPACE 7 /* POSIX space - Z plus 9,10,11,12,13 */
+#define PT_WORD 8 /* Word - L plus N plus underscore */
+#define PT_CLIST 9 /* Pseudo-property: match character list */
+#define PT_UCNC 10 /* Universal Character nameable character */
+#define PT_TABSIZE 11 /* Size of square table for autopossessify tests */
+
+/* The following special properties are used only in XCLASS items, when POSIX
+classes are specified and PCRE2_UCP is set - in other words, for Unicode
+handling of these classes. They are not available via the \p or \P escapes like
+those in the above list, and so they do not take part in the autopossessifying
+table. */
+
+#define PT_PXGRAPH 11 /* [:graph:] - characters that mark the paper */
+#define PT_PXPRINT 12 /* [:print:] - [:graph:] plus non-control spaces */
+#define PT_PXPUNCT 13 /* [:punct:] - punctuation characters */
+
+/* Flag bits and data types for the extended class (OP_XCLASS) for classes that
+contain characters with values greater than 255. */
+
+#define XCL_NOT 0x01 /* Flag: this is a negative class */
+#define XCL_MAP 0x02 /* Flag: a 32-byte map is present */
+#define XCL_HASPROP 0x04 /* Flag: property checks are present. */
+
+#define XCL_END 0 /* Marks end of individual items */
+#define XCL_SINGLE 1 /* Single item (one multibyte char) follows */
+#define XCL_RANGE 2 /* A range (two multibyte chars) follows */
+#define XCL_PROP 3 /* Unicode property (2-byte property code follows) */
+#define XCL_NOTPROP 4 /* Unicode inverted property (ditto) */
+
+/* These are escaped items that aren't just an encoding of a particular data
+value such as \n. They must have non-zero values, as check_escape() returns 0
+for a data character. In the escapes[] table in pcre2_compile.c their values
+are negated in order to distinguish them from data values.
+
+They must appear here in the same order as in the opcode definitions below, up
+to ESC_z. There's a dummy for OP_ALLANY because it corresponds to "." in DOTALL
+mode rather than an escape sequence. It is also used for [^] in JavaScript
+compatibility mode, and for \C in non-utf mode. In non-DOTALL mode, "." behaves
+like \N.
+
+Negative numbers are used to encode a backreference (\1, \2, \3, etc.) in
+check_escape(). There are tests in the code for an escape greater than ESC_b
+and less than ESC_Z to detect the types that may be repeated. These are the
+types that consume characters. If any new escapes are put in between that don't
+consume a character, that code will have to change. */
+
+enum { ESC_A = 1, ESC_G, ESC_K, ESC_B, ESC_b, ESC_D, ESC_d, ESC_S, ESC_s,
+ ESC_W, ESC_w, ESC_N, ESC_dum, ESC_C, ESC_P, ESC_p, ESC_R, ESC_H,
+ ESC_h, ESC_V, ESC_v, ESC_X, ESC_Z, ESC_z,
+ ESC_E, ESC_Q, ESC_g, ESC_k };
+
+
+/********************** Opcode definitions ******************/
+
+/****** NOTE NOTE NOTE ******
+
+Starting from 1 (i.e. after OP_END), the values up to OP_EOD must correspond in
+order to the list of escapes immediately above. Furthermore, values up to
+OP_DOLLM must not be changed without adjusting the table called autoposstab in
+pcre2_auto_possess.c
+
+Whenever this list is updated, the two macro definitions that follow must be
+updated to match. The possessification table called "opcode_possessify" in
+pcre2_compile.c must also be updated, and also the tables called "coptable"
+and "poptable" in pcre2_dfa_match.c.
+
+****** NOTE NOTE NOTE ******/
+
+
+/* The values between FIRST_AUTOTAB_OP and LAST_AUTOTAB_RIGHT_OP, inclusive,
+are used in a table for deciding whether a repeated character type can be
+auto-possessified. */
+
+#define FIRST_AUTOTAB_OP OP_NOT_DIGIT
+#define LAST_AUTOTAB_LEFT_OP OP_EXTUNI
+#define LAST_AUTOTAB_RIGHT_OP OP_DOLLM
+
+enum {
+ OP_END, /* 0 End of pattern */
+
+ /* Values corresponding to backslashed metacharacters */
+
+ OP_SOD, /* 1 Start of data: \A */
+ OP_SOM, /* 2 Start of match (subject + offset): \G */
+ OP_SET_SOM, /* 3 Set start of match (\K) */
+ OP_NOT_WORD_BOUNDARY, /* 4 \B */
+ OP_WORD_BOUNDARY, /* 5 \b */
+ OP_NOT_DIGIT, /* 6 \D */
+ OP_DIGIT, /* 7 \d */
+ OP_NOT_WHITESPACE, /* 8 \S */
+ OP_WHITESPACE, /* 9 \s */
+ OP_NOT_WORDCHAR, /* 10 \W */
+ OP_WORDCHAR, /* 11 \w */
+
+ OP_ANY, /* 12 Match any character except newline (\N) */
+ OP_ALLANY, /* 13 Match any character */
+ OP_ANYBYTE, /* 14 Match any byte (\C); different to OP_ANY for UTF-8 */
+ OP_NOTPROP, /* 15 \P (not Unicode property) */
+ OP_PROP, /* 16 \p (Unicode property) */
+ OP_ANYNL, /* 17 \R (any newline sequence) */
+ OP_NOT_HSPACE, /* 18 \H (not horizontal whitespace) */
+ OP_HSPACE, /* 19 \h (horizontal whitespace) */
+ OP_NOT_VSPACE, /* 20 \V (not vertical whitespace) */
+ OP_VSPACE, /* 21 \v (vertical whitespace) */
+ OP_EXTUNI, /* 22 \X (extended Unicode sequence */
+ OP_EODN, /* 23 End of data or \n at end of data (\Z) */
+ OP_EOD, /* 24 End of data (\z) */
+
+ /* Line end assertions */
+
+ OP_DOLL, /* 25 End of line - not multiline */
+ OP_DOLLM, /* 26 End of line - multiline */
+ OP_CIRC, /* 27 Start of line - not multiline */
+ OP_CIRCM, /* 28 Start of line - multiline */
+
+ /* Single characters; caseful must precede the caseless ones, and these
+ must remain in this order, and adjacent. */
+
+ OP_CHAR, /* 29 Match one character, casefully */
+ OP_CHARI, /* 30 Match one character, caselessly */
+ OP_NOT, /* 31 Match one character, not the given one, casefully */
+ OP_NOTI, /* 32 Match one character, not the given one, caselessly */
+
+ /* The following sets of 13 opcodes must always be kept in step because
+ the offset from the first one is used to generate the others. */
+
+ /* Repeated characters; caseful must precede the caseless ones */
+
+ OP_STAR, /* 33 The maximizing and minimizing versions of */
+ OP_MINSTAR, /* 34 these six opcodes must come in pairs, with */
+ OP_PLUS, /* 35 the minimizing one second. */
+ OP_MINPLUS, /* 36 */
+ OP_QUERY, /* 37 */
+ OP_MINQUERY, /* 38 */
+
+ OP_UPTO, /* 39 From 0 to n matches of one character, caseful*/
+ OP_MINUPTO, /* 40 */
+ OP_EXACT, /* 41 Exactly n matches */
+
+ OP_POSSTAR, /* 42 Possessified star, caseful */
+ OP_POSPLUS, /* 43 Possessified plus, caseful */
+ OP_POSQUERY, /* 44 Posesssified query, caseful */
+ OP_POSUPTO, /* 45 Possessified upto, caseful */
+
+ /* Repeated characters; caseless must follow the caseful ones */
+
+ OP_STARI, /* 46 */
+ OP_MINSTARI, /* 47 */
+ OP_PLUSI, /* 48 */
+ OP_MINPLUSI, /* 49 */
+ OP_QUERYI, /* 50 */
+ OP_MINQUERYI, /* 51 */
+
+ OP_UPTOI, /* 52 From 0 to n matches of one character, caseless */
+ OP_MINUPTOI, /* 53 */
+ OP_EXACTI, /* 54 */
+
+ OP_POSSTARI, /* 55 Possessified star, caseless */
+ OP_POSPLUSI, /* 56 Possessified plus, caseless */
+ OP_POSQUERYI, /* 57 Posesssified query, caseless */
+ OP_POSUPTOI, /* 58 Possessified upto, caseless */
+
+ /* The negated ones must follow the non-negated ones, and match them */
+ /* Negated repeated character, caseful; must precede the caseless ones */
+
+ OP_NOTSTAR, /* 59 The maximizing and minimizing versions of */
+ OP_NOTMINSTAR, /* 60 these six opcodes must come in pairs, with */
+ OP_NOTPLUS, /* 61 the minimizing one second. They must be in */
+ OP_NOTMINPLUS, /* 62 exactly the same order as those above. */
+ OP_NOTQUERY, /* 63 */
+ OP_NOTMINQUERY, /* 64 */
+
+ OP_NOTUPTO, /* 65 From 0 to n matches, caseful */
+ OP_NOTMINUPTO, /* 66 */
+ OP_NOTEXACT, /* 67 Exactly n matches */
+
+ OP_NOTPOSSTAR, /* 68 Possessified versions, caseful */
+ OP_NOTPOSPLUS, /* 69 */
+ OP_NOTPOSQUERY, /* 70 */
+ OP_NOTPOSUPTO, /* 71 */
+
+ /* Negated repeated character, caseless; must follow the caseful ones */
+
+ OP_NOTSTARI, /* 72 */
+ OP_NOTMINSTARI, /* 73 */
+ OP_NOTPLUSI, /* 74 */
+ OP_NOTMINPLUSI, /* 75 */
+ OP_NOTQUERYI, /* 76 */
+ OP_NOTMINQUERYI, /* 77 */
+
+ OP_NOTUPTOI, /* 78 From 0 to n matches, caseless */
+ OP_NOTMINUPTOI, /* 79 */
+ OP_NOTEXACTI, /* 80 Exactly n matches */
+
+ OP_NOTPOSSTARI, /* 81 Possessified versions, caseless */
+ OP_NOTPOSPLUSI, /* 82 */
+ OP_NOTPOSQUERYI, /* 83 */
+ OP_NOTPOSUPTOI, /* 84 */
+
+ /* Character types */
+
+ OP_TYPESTAR, /* 85 The maximizing and minimizing versions of */
+ OP_TYPEMINSTAR, /* 86 these six opcodes must come in pairs, with */
+ OP_TYPEPLUS, /* 87 the minimizing one second. These codes must */
+ OP_TYPEMINPLUS, /* 88 be in exactly the same order as those above. */
+ OP_TYPEQUERY, /* 89 */
+ OP_TYPEMINQUERY, /* 90 */
+
+ OP_TYPEUPTO, /* 91 From 0 to n matches */
+ OP_TYPEMINUPTO, /* 92 */
+ OP_TYPEEXACT, /* 93 Exactly n matches */
+
+ OP_TYPEPOSSTAR, /* 94 Possessified versions */
+ OP_TYPEPOSPLUS, /* 95 */
+ OP_TYPEPOSQUERY, /* 96 */
+ OP_TYPEPOSUPTO, /* 97 */
+
+ /* These are used for character classes and back references; only the
+ first six are the same as the sets above. */
+
+ OP_CRSTAR, /* 98 The maximizing and minimizing versions of */
+ OP_CRMINSTAR, /* 99 all these opcodes must come in pairs, with */
+ OP_CRPLUS, /* 100 the minimizing one second. These codes must */
+ OP_CRMINPLUS, /* 101 be in exactly the same order as those above. */
+ OP_CRQUERY, /* 102 */
+ OP_CRMINQUERY, /* 103 */
+
+ OP_CRRANGE, /* 104 These are different to the three sets above. */
+ OP_CRMINRANGE, /* 105 */
+
+ OP_CRPOSSTAR, /* 106 Possessified versions */
+ OP_CRPOSPLUS, /* 107 */
+ OP_CRPOSQUERY, /* 108 */
+ OP_CRPOSRANGE, /* 109 */
+
+ /* End of quantifier opcodes */
+
+ OP_CLASS, /* 110 Match a character class, chars < 256 only */
+ OP_NCLASS, /* 111 Same, but the bitmap was created from a negative
+ class - the difference is relevant only when a
+ character > 255 is encountered. */
+ OP_XCLASS, /* 112 Extended class for handling > 255 chars within the
+ class. This does both positive and negative. */
+ OP_REF, /* 113 Match a back reference, casefully */
+ OP_REFI, /* 114 Match a back reference, caselessly */
+ OP_DNREF, /* 115 Match a duplicate name backref, casefully */
+ OP_DNREFI, /* 116 Match a duplicate name backref, caselessly */
+ OP_RECURSE, /* 117 Match a numbered subpattern (possibly recursive) */
+ OP_CALLOUT, /* 118 Call out to external function if provided */
+ OP_CALLOUT_STR, /* 119 Call out with string argument */
+
+ OP_ALT, /* 120 Start of alternation */
+ OP_KET, /* 121 End of group that doesn't have an unbounded repeat */
+ OP_KETRMAX, /* 122 These two must remain together and in this */
+ OP_KETRMIN, /* 123 order. They are for groups the repeat for ever. */
+ OP_KETRPOS, /* 124 Possessive unlimited repeat. */
+
+ /* The assertions must come before BRA, CBRA, ONCE, and COND, and the four
+ asserts must remain in order. */
+
+ OP_REVERSE, /* 125 Move pointer back - used in lookbehind assertions */
+ OP_ASSERT, /* 126 Positive lookahead */
+ OP_ASSERT_NOT, /* 127 Negative lookahead */
+ OP_ASSERTBACK, /* 128 Positive lookbehind */
+ OP_ASSERTBACK_NOT, /* 129 Negative lookbehind */
+
+ /* ONCE, BRA, BRAPOS, CBRA, CBRAPOS, and COND must come immediately after the
+ assertions, with ONCE first, as there's a test for >= ONCE for a subpattern
+ that isn't an assertion. The POS versions must immediately follow the non-POS
+ versions in each case. */
+
+ OP_ONCE, /* 130 Atomic group, contains captures */
+ OP_BRA, /* 131 Start of non-capturing bracket */
+ OP_BRAPOS, /* 132 Ditto, with unlimited, possessive repeat */
+ OP_CBRA, /* 133 Start of capturing bracket */
+ OP_CBRAPOS, /* 134 Ditto, with unlimited, possessive repeat */
+ OP_COND, /* 135 Conditional group */
+
+ /* These five must follow the previous five, in the same order. There's a
+ check for >= SBRA to distinguish the two sets. */
+
+ OP_SBRA, /* 136 Start of non-capturing bracket, check empty */
+ OP_SBRAPOS, /* 137 Ditto, with unlimited, possessive repeat */
+ OP_SCBRA, /* 138 Start of capturing bracket, check empty */
+ OP_SCBRAPOS, /* 139 Ditto, with unlimited, possessive repeat */
+ OP_SCOND, /* 140 Conditional group, check empty */
+
+ /* The next two pairs must (respectively) be kept together. */
+
+ OP_CREF, /* 141 Used to hold a capture number as condition */
+ OP_DNCREF, /* 142 Used to point to duplicate names as a condition */
+ OP_RREF, /* 143 Used to hold a recursion number as condition */
+ OP_DNRREF, /* 144 Used to point to duplicate names as a condition */
+ OP_FALSE, /* 145 Always false (used by DEFINE and VERSION) */
+ OP_TRUE, /* 146 Always true (used by VERSION) */
+
+ OP_BRAZERO, /* 147 These two must remain together and in this */
+ OP_BRAMINZERO, /* 148 order. */
+ OP_BRAPOSZERO, /* 149 */
+
+ /* These are backtracking control verbs */
+
+ OP_MARK, /* 150 always has an argument */
+ OP_PRUNE, /* 151 */
+ OP_PRUNE_ARG, /* 152 same, but with argument */
+ OP_SKIP, /* 153 */
+ OP_SKIP_ARG, /* 154 same, but with argument */
+ OP_THEN, /* 155 */
+ OP_THEN_ARG, /* 156 same, but with argument */
+ OP_COMMIT, /* 157 */
+ OP_COMMIT_ARG, /* 158 same, but with argument */
+
+ /* These are forced failure and success verbs. FAIL and ACCEPT do accept an
+ argument, but these cases can be compiled as, for example, (*MARK:X)(*FAIL)
+ without the need for a special opcode. */
+
+ OP_FAIL, /* 159 */
+ OP_ACCEPT, /* 160 */
+ OP_ASSERT_ACCEPT, /* 161 Used inside assertions */
+ OP_CLOSE, /* 162 Used before OP_ACCEPT to close open captures */
+
+ /* This is used to skip a subpattern with a {0} quantifier */
+
+ OP_SKIPZERO, /* 163 */
+
+ /* This is used to identify a DEFINE group during compilation so that it can
+ be checked for having only one branch. It is changed to OP_FALSE before
+ compilation finishes. */
+
+ OP_DEFINE, /* 164 */
+
+ /* This is not an opcode, but is used to check that tables indexed by opcode
+ are the correct length, in order to catch updating errors - there have been
+ some in the past. */
+
+ OP_TABLE_LENGTH
+
+};
+
+/* *** NOTE NOTE NOTE *** Whenever the list above is updated, the two macro
+definitions that follow must also be updated to match. There are also tables
+called "opcode_possessify" in pcre2_compile.c and "coptable" and "poptable" in
+pcre2_dfa_exec.c that must be updated. */
+
+
+/* This macro defines textual names for all the opcodes. These are used only
+for debugging, and some of them are only partial names. The macro is referenced
+only in pcre2_printint.c, which fills out the full names in many cases (and in
+some cases doesn't actually use these names at all). */
+
+#define OP_NAME_LIST \
+ "End", "\\A", "\\G", "\\K", "\\B", "\\b", "\\D", "\\d", \
+ "\\S", "\\s", "\\W", "\\w", "Any", "AllAny", "Anybyte", \
+ "notprop", "prop", "\\R", "\\H", "\\h", "\\V", "\\v", \
+ "extuni", "\\Z", "\\z", \
+ "$", "$", "^", "^", "char", "chari", "not", "noti", \
+ "*", "*?", "+", "+?", "?", "??", \
+ "{", "{", "{", \
+ "*+","++", "?+", "{", \
+ "*", "*?", "+", "+?", "?", "??", \
+ "{", "{", "{", \
+ "*+","++", "?+", "{", \
+ "*", "*?", "+", "+?", "?", "??", \
+ "{", "{", "{", \
+ "*+","++", "?+", "{", \
+ "*", "*?", "+", "+?", "?", "??", \
+ "{", "{", "{", \
+ "*+","++", "?+", "{", \
+ "*", "*?", "+", "+?", "?", "??", "{", "{", "{", \
+ "*+","++", "?+", "{", \
+ "*", "*?", "+", "+?", "?", "??", "{", "{", \
+ "*+","++", "?+", "{", \
+ "class", "nclass", "xclass", "Ref", "Refi", "DnRef", "DnRefi", \
+ "Recurse", "Callout", "CalloutStr", \
+ "Alt", "Ket", "KetRmax", "KetRmin", "KetRpos", \
+ "Reverse", "Assert", "Assert not", "AssertB", "AssertB not", \
+ "Once", \
+ "Bra", "BraPos", "CBra", "CBraPos", \
+ "Cond", \
+ "SBra", "SBraPos", "SCBra", "SCBraPos", \
+ "SCond", \
+ "Cond ref", "Cond dnref", "Cond rec", "Cond dnrec", \
+ "Cond false", "Cond true", \
+ "Brazero", "Braminzero", "Braposzero", \
+ "*MARK", "*PRUNE", "*PRUNE", "*SKIP", "*SKIP", \
+ "*THEN", "*THEN", "*COMMIT", "*COMMIT", "*FAIL", \
+ "*ACCEPT", "*ASSERT_ACCEPT", \
+ "Close", "Skip zero", "Define"
+
+
+/* This macro defines the length of fixed length operations in the compiled
+regex. The lengths are used when searching for specific things, and also in the
+debugging printing of a compiled regex. We use a macro so that it can be
+defined close to the definitions of the opcodes themselves.
+
+As things have been extended, some of these are no longer fixed lenths, but are
+minima instead. For example, the length of a single-character repeat may vary
+in UTF-8 mode. The code that uses this table must know about such things. */
+
+#define OP_LENGTHS \
+ 1, /* End */ \
+ 1, 1, 1, 1, 1, /* \A, \G, \K, \B, \b */ \
+ 1, 1, 1, 1, 1, 1, /* \D, \d, \S, \s, \W, \w */ \
+ 1, 1, 1, /* Any, AllAny, Anybyte */ \
+ 3, 3, /* \P, \p */ \
+ 1, 1, 1, 1, 1, /* \R, \H, \h, \V, \v */ \
+ 1, /* \X */ \
+ 1, 1, 1, 1, 1, 1, /* \Z, \z, $, $M ^, ^M */ \
+ 2, /* Char - the minimum length */ \
+ 2, /* Chari - the minimum length */ \
+ 2, /* not */ \
+ 2, /* noti */ \
+ /* Positive single-char repeats ** These are */ \
+ 2, 2, 2, 2, 2, 2, /* *, *?, +, +?, ?, ?? ** minima in */ \
+ 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto, minupto ** mode */ \
+ 2+IMM2_SIZE, /* exact */ \
+ 2, 2, 2, 2+IMM2_SIZE, /* *+, ++, ?+, upto+ */ \
+ 2, 2, 2, 2, 2, 2, /* *I, *?I, +I, +?I, ?I, ??I ** UTF-8 */ \
+ 2+IMM2_SIZE, 2+IMM2_SIZE, /* upto I, minupto I */ \
+ 2+IMM2_SIZE, /* exact I */ \
+ 2, 2, 2, 2+IMM2_SIZE, /* *+I, ++I, ?+I, upto+I */ \
+ /* Negative single-char repeats - only for chars < 256 */ \
+ 2, 2, 2, 2, 2, 2, /* NOT *, *?, +, +?, ?, ?? */ \
+ 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto, minupto */ \
+ 2+IMM2_SIZE, /* NOT exact */ \
+ 2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *, +, ?, upto */ \
+ 2, 2, 2, 2, 2, 2, /* NOT *I, *?I, +I, +?I, ?I, ??I */ \
+ 2+IMM2_SIZE, 2+IMM2_SIZE, /* NOT upto I, minupto I */ \
+ 2+IMM2_SIZE, /* NOT exact I */ \
+ 2, 2, 2, 2+IMM2_SIZE, /* Possessive NOT *I, +I, ?I, upto I */ \
+ /* Positive type repeats */ \
+ 2, 2, 2, 2, 2, 2, /* Type *, *?, +, +?, ?, ?? */ \
+ 2+IMM2_SIZE, 2+IMM2_SIZE, /* Type upto, minupto */ \
+ 2+IMM2_SIZE, /* Type exact */ \
+ 2, 2, 2, 2+IMM2_SIZE, /* Possessive *+, ++, ?+, upto+ */ \
+ /* Character class & ref repeats */ \
+ 1, 1, 1, 1, 1, 1, /* *, *?, +, +?, ?, ?? */ \
+ 1+2*IMM2_SIZE, 1+2*IMM2_SIZE, /* CRRANGE, CRMINRANGE */ \
+ 1, 1, 1, 1+2*IMM2_SIZE, /* Possessive *+, ++, ?+, CRPOSRANGE */ \
+ 1+(32/sizeof(PCRE2_UCHAR)), /* CLASS */ \
+ 1+(32/sizeof(PCRE2_UCHAR)), /* NCLASS */ \
+ 0, /* XCLASS - variable length */ \
+ 1+IMM2_SIZE, /* REF */ \
+ 1+IMM2_SIZE, /* REFI */ \
+ 1+2*IMM2_SIZE, /* DNREF */ \
+ 1+2*IMM2_SIZE, /* DNREFI */ \
+ 1+LINK_SIZE, /* RECURSE */ \
+ 1+2*LINK_SIZE+1, /* CALLOUT */ \
+ 0, /* CALLOUT_STR - variable length */ \
+ 1+LINK_SIZE, /* Alt */ \
+ 1+LINK_SIZE, /* Ket */ \
+ 1+LINK_SIZE, /* KetRmax */ \
+ 1+LINK_SIZE, /* KetRmin */ \
+ 1+LINK_SIZE, /* KetRpos */ \
+ 1+LINK_SIZE, /* Reverse */ \
+ 1+LINK_SIZE, /* Assert */ \
+ 1+LINK_SIZE, /* Assert not */ \
+ 1+LINK_SIZE, /* Assert behind */ \
+ 1+LINK_SIZE, /* Assert behind not */ \
+ 1+LINK_SIZE, /* ONCE */ \
+ 1+LINK_SIZE, /* BRA */ \
+ 1+LINK_SIZE, /* BRAPOS */ \
+ 1+LINK_SIZE+IMM2_SIZE, /* CBRA */ \
+ 1+LINK_SIZE+IMM2_SIZE, /* CBRAPOS */ \
+ 1+LINK_SIZE, /* COND */ \
+ 1+LINK_SIZE, /* SBRA */ \
+ 1+LINK_SIZE, /* SBRAPOS */ \
+ 1+LINK_SIZE+IMM2_SIZE, /* SCBRA */ \
+ 1+LINK_SIZE+IMM2_SIZE, /* SCBRAPOS */ \
+ 1+LINK_SIZE, /* SCOND */ \
+ 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* CREF, DNCREF */ \
+ 1+IMM2_SIZE, 1+2*IMM2_SIZE, /* RREF, DNRREF */ \
+ 1, 1, /* FALSE, TRUE */ \
+ 1, 1, 1, /* BRAZERO, BRAMINZERO, BRAPOSZERO */ \
+ 3, 1, 3, /* MARK, PRUNE, PRUNE_ARG */ \
+ 1, 3, /* SKIP, SKIP_ARG */ \
+ 1, 3, /* THEN, THEN_ARG */ \
+ 1, 3, /* COMMIT, COMMIT_ARG */ \
+ 1, 1, 1, /* FAIL, ACCEPT, ASSERT_ACCEPT */ \
+ 1+IMM2_SIZE, 1, /* CLOSE, SKIPZERO */ \
+ 1 /* DEFINE */
+
+/* A magic value for OP_RREF to indicate the "any recursion" condition. */
+
+#define RREF_ANY 0xffff
+
+
+/* ---------- Private structures that are mode-independent. ---------- */
+
+/* Structure to hold data for custom memory management. */
+
+typedef struct pcre2_memctl {
+ void * (*malloc)(size_t, void *);
+ void (*free)(void *, void *);
+ void *memory_data;
+} pcre2_memctl;
+
+/* Structure for building a chain of open capturing subpatterns during
+compiling, so that instructions to close them can be compiled when (*ACCEPT) is
+encountered. This is also used to identify subpatterns that contain recursive
+back references to themselves, so that they can be made atomic. */
+
+typedef struct open_capitem {
+ struct open_capitem *next; /* Chain link */
+ uint16_t number; /* Capture number */
+ uint16_t flag; /* Set TRUE if recursive back ref */
+ uint16_t assert_depth; /* Assertion depth when opened */
+} open_capitem;
+
+/* Layout of the UCP type table that translates property names into types and
+codes. Each entry used to point directly to a name, but to reduce the number of
+relocations in shared libraries, it now has an offset into a single string
+instead. */
+
+typedef struct {
+ uint16_t name_offset;
+ uint16_t type;
+ uint16_t value;
+} ucp_type_table;
+
+/* Unicode character database (UCD) record format */
+
+typedef struct {
+ uint8_t script; /* ucp_Arabic, etc. */
+ uint8_t chartype; /* ucp_Cc, etc. (general categories) */
+ uint8_t gbprop; /* ucp_gbControl, etc. (grapheme break property) */
+ uint8_t caseset; /* offset to multichar other cases or zero */
+ int32_t other_case; /* offset to other case, or zero if none */
+} ucd_record;
+
+/* UCD access macros */
+
+#define UCD_BLOCK_SIZE 128
+#define REAL_GET_UCD(ch) (PRIV(ucd_records) + \
+ PRIV(ucd_stage2)[PRIV(ucd_stage1)[(int)(ch) / UCD_BLOCK_SIZE] * \
+ UCD_BLOCK_SIZE + (int)(ch) % UCD_BLOCK_SIZE])
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define GET_UCD(ch) ((ch > MAX_UTF_CODE_POINT)? \
+ PRIV(dummy_ucd_record) : REAL_GET_UCD(ch))
+#else
+#define GET_UCD(ch) REAL_GET_UCD(ch)
+#endif
+
+#define UCD_CHARTYPE(ch) GET_UCD(ch)->chartype
+#define UCD_SCRIPT(ch) GET_UCD(ch)->script
+#define UCD_CATEGORY(ch) PRIV(ucp_gentype)[UCD_CHARTYPE(ch)]
+#define UCD_GRAPHBREAK(ch) GET_UCD(ch)->gbprop
+#define UCD_CASESET(ch) GET_UCD(ch)->caseset
+#define UCD_OTHERCASE(ch) ((uint32_t)((int)ch + (int)(GET_UCD(ch)->other_case)))
+
+/* Header for serialized pcre2 codes. */
+
+typedef struct pcre2_serialized_data {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t config;
+ int32_t number_of_codes;
+} pcre2_serialized_data;
+
+
+
+/* ----------------- Items that need PCRE2_CODE_UNIT_WIDTH ----------------- */
+
+/* When this file is included by pcre2test, PCRE2_CODE_UNIT_WIDTH is defined as
+0, so the following items are omitted. */
+
+#if defined PCRE2_CODE_UNIT_WIDTH && PCRE2_CODE_UNIT_WIDTH != 0
+
+/* EBCDIC is supported only for the 8-bit library. */
+
+#if defined EBCDIC && PCRE2_CODE_UNIT_WIDTH != 8
+#error EBCDIC is not supported for the 16-bit or 32-bit libraries
+#endif
+
+/* This is the largest non-UTF code point. */
+
+#define MAX_NON_UTF_CHAR (0xffffffffU >> (32 - PCRE2_CODE_UNIT_WIDTH))
+
+/* Internal shared data tables and variables. These are used by more than one
+of the exported public functions. They have to be "external" in the C sense,
+but are not part of the PCRE2 public API. Although the data for some of them is
+identical in all libraries, they must have different names so that multiple
+libraries can be simultaneously linked to a single application. However, UTF-8
+tables are needed only when compiling the 8-bit library. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+extern const int PRIV(utf8_table1)[];
+extern const int PRIV(utf8_table1_size);
+extern const int PRIV(utf8_table2)[];
+extern const int PRIV(utf8_table3)[];
+extern const uint8_t PRIV(utf8_table4)[];
+#endif
+
+#define _pcre2_OP_lengths PCRE2_SUFFIX(_pcre2_OP_lengths_)
+#define _pcre2_callout_end_delims PCRE2_SUFFIX(_pcre2_callout_end_delims_)
+#define _pcre2_callout_start_delims PCRE2_SUFFIX(_pcre2_callout_start_delims_)
+#define _pcre2_default_compile_context PCRE2_SUFFIX(_pcre2_default_compile_context_)
+#define _pcre2_default_convert_context PCRE2_SUFFIX(_pcre2_default_convert_context_)
+#define _pcre2_default_match_context PCRE2_SUFFIX(_pcre2_default_match_context_)
+#define _pcre2_default_tables PCRE2_SUFFIX(_pcre2_default_tables_)
+#if PCRE2_CODE_UNIT_WIDTH == 32
+#define _pcre2_dummy_ucd_record PCRE2_SUFFIX(_pcre2_dummy_ucd_record_)
+#endif
+#define _pcre2_hspace_list PCRE2_SUFFIX(_pcre2_hspace_list_)
+#define _pcre2_vspace_list PCRE2_SUFFIX(_pcre2_vspace_list_)
+#define _pcre2_ucd_caseless_sets PCRE2_SUFFIX(_pcre2_ucd_caseless_sets_)
+#define _pcre2_ucd_records PCRE2_SUFFIX(_pcre2_ucd_records_)
+#define _pcre2_ucd_stage1 PCRE2_SUFFIX(_pcre2_ucd_stage1_)
+#define _pcre2_ucd_stage2 PCRE2_SUFFIX(_pcre2_ucd_stage2_)
+#define _pcre2_ucp_gbtable PCRE2_SUFFIX(_pcre2_ucp_gbtable_)
+#define _pcre2_ucp_gentype PCRE2_SUFFIX(_pcre2_ucp_gentype_)
+#define _pcre2_ucp_typerange PCRE2_SUFFIX(_pcre2_ucp_typerange_)
+#define _pcre2_unicode_version PCRE2_SUFFIX(_pcre2_unicode_version_)
+#define _pcre2_utt PCRE2_SUFFIX(_pcre2_utt_)
+#define _pcre2_utt_names PCRE2_SUFFIX(_pcre2_utt_names_)
+#define _pcre2_utt_size PCRE2_SUFFIX(_pcre2_utt_size_)
+
+extern const uint8_t PRIV(OP_lengths)[];
+extern const uint32_t PRIV(callout_end_delims)[];
+extern const uint32_t PRIV(callout_start_delims)[];
+extern const pcre2_compile_context PRIV(default_compile_context);
+extern const pcre2_convert_context PRIV(default_convert_context);
+extern const pcre2_match_context PRIV(default_match_context);
+extern const uint8_t PRIV(default_tables)[];
+extern const uint32_t PRIV(hspace_list)[];
+extern const uint32_t PRIV(vspace_list)[];
+extern const uint32_t PRIV(ucd_caseless_sets)[];
+extern const ucd_record PRIV(ucd_records)[];
+#if PCRE2_CODE_UNIT_WIDTH == 32
+extern const ucd_record PRIV(dummy_ucd_record)[];
+#endif
+extern const uint16_t PRIV(ucd_stage1)[];
+extern const uint16_t PRIV(ucd_stage2)[];
+extern const uint32_t PRIV(ucp_gbtable)[];
+extern const uint32_t PRIV(ucp_gentype)[];
+#ifdef SUPPORT_JIT
+extern const int PRIV(ucp_typerange)[];
+#endif
+extern const char *PRIV(unicode_version);
+extern const ucp_type_table PRIV(utt)[];
+extern const char PRIV(utt_names)[];
+extern const size_t PRIV(utt_size);
+
+/* Mode-dependent macros and hidden and private structures are defined in a
+separate file so that pcre2test can include them at all supported widths. When
+compiling the library, PCRE2_CODE_UNIT_WIDTH will be defined, and we can
+include them at the appropriate width, after setting up suffix macros for the
+private structures. */
+
+#define branch_chain PCRE2_SUFFIX(branch_chain_)
+#define compile_block PCRE2_SUFFIX(compile_block_)
+#define dfa_match_block PCRE2_SUFFIX(dfa_match_block_)
+#define match_block PCRE2_SUFFIX(match_block_)
+#define named_group PCRE2_SUFFIX(named_group_)
+
+#include "pcre2_intmodedep.h"
+
+/* Private "external" functions. These are internal functions that are called
+from modules other than the one in which they are defined. They have to be
+"external" in the C sense, but are not part of the PCRE2 public API. They are
+not referenced from pcre2test, and must not be defined when no code unit width
+is available. */
+
+#define _pcre2_auto_possessify PCRE2_SUFFIX(_pcre2_auto_possessify_)
+#define _pcre2_check_escape PCRE2_SUFFIX(_pcre2_check_escape_)
+#define _pcre2_extuni PCRE2_SUFFIX(_pcre2_extuni_)
+#define _pcre2_find_bracket PCRE2_SUFFIX(_pcre2_find_bracket_)
+#define _pcre2_is_newline PCRE2_SUFFIX(_pcre2_is_newline_)
+#define _pcre2_jit_free_rodata PCRE2_SUFFIX(_pcre2_jit_free_rodata_)
+#define _pcre2_jit_free PCRE2_SUFFIX(_pcre2_jit_free_)
+#define _pcre2_jit_get_size PCRE2_SUFFIX(_pcre2_jit_get_size_)
+#define _pcre2_jit_get_target PCRE2_SUFFIX(_pcre2_jit_get_target_)
+#define _pcre2_memctl_malloc PCRE2_SUFFIX(_pcre2_memctl_malloc_)
+#define _pcre2_ord2utf PCRE2_SUFFIX(_pcre2_ord2utf_)
+#define _pcre2_strcmp PCRE2_SUFFIX(_pcre2_strcmp_)
+#define _pcre2_strcmp_c8 PCRE2_SUFFIX(_pcre2_strcmp_c8_)
+#define _pcre2_strcpy_c8 PCRE2_SUFFIX(_pcre2_strcpy_c8_)
+#define _pcre2_strlen PCRE2_SUFFIX(_pcre2_strlen_)
+#define _pcre2_strncmp PCRE2_SUFFIX(_pcre2_strncmp_)
+#define _pcre2_strncmp_c8 PCRE2_SUFFIX(_pcre2_strncmp_c8_)
+#define _pcre2_study PCRE2_SUFFIX(_pcre2_study_)
+#define _pcre2_valid_utf PCRE2_SUFFIX(_pcre2_valid_utf_)
+#define _pcre2_was_newline PCRE2_SUFFIX(_pcre2_was_newline_)
+#define _pcre2_xclass PCRE2_SUFFIX(_pcre2_xclass_)
+
+extern int _pcre2_auto_possessify(PCRE2_UCHAR *, BOOL,
+ const compile_block *);
+extern int _pcre2_check_escape(PCRE2_SPTR *, PCRE2_SPTR, uint32_t *,
+ int *, uint32_t, BOOL, compile_block *);
+extern PCRE2_SPTR _pcre2_extuni(uint32_t, PCRE2_SPTR, PCRE2_SPTR, PCRE2_SPTR,
+ BOOL, int *);
+extern PCRE2_SPTR _pcre2_find_bracket(PCRE2_SPTR, BOOL, int);
+extern BOOL _pcre2_is_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+ uint32_t *, BOOL);
+extern void _pcre2_jit_free_rodata(void *, void *);
+extern void _pcre2_jit_free(void *, pcre2_memctl *);
+extern size_t _pcre2_jit_get_size(void *);
+const char * _pcre2_jit_get_target(void);
+extern void * _pcre2_memctl_malloc(size_t, pcre2_memctl *);
+extern unsigned int _pcre2_ord2utf(uint32_t, PCRE2_UCHAR *);
+extern int _pcre2_strcmp(PCRE2_SPTR, PCRE2_SPTR);
+extern int _pcre2_strcmp_c8(PCRE2_SPTR, const char *);
+extern PCRE2_SIZE _pcre2_strcpy_c8(PCRE2_UCHAR *, const char *);
+extern PCRE2_SIZE _pcre2_strlen(PCRE2_SPTR);
+extern int _pcre2_strncmp(PCRE2_SPTR, PCRE2_SPTR, size_t);
+extern int _pcre2_strncmp_c8(PCRE2_SPTR, const char *, size_t);
+extern int _pcre2_study(pcre2_real_code *);
+extern int _pcre2_valid_utf(PCRE2_SPTR, PCRE2_SIZE, PCRE2_SIZE *);
+extern BOOL _pcre2_was_newline(PCRE2_SPTR, uint32_t, PCRE2_SPTR,
+ uint32_t *, BOOL);
+extern BOOL _pcre2_xclass(uint32_t, PCRE2_SPTR, BOOL);
+
+/* This function is needed only when memmove() is not available. */
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+#define _pcre2_memmove PCRE2_SUFFIX(_pcre2_memmove)
+extern void * _pcre2_memmove(void *, const void *, size_t);
+#endif
+
+#endif /* PCRE2_CODE_UNIT_WIDTH */
+#endif /* PCRE2_INTERNAL_H_IDEMPOTENT_GUARD */
+
+/* End of pcre2_internal.h */
diff --git a/test/monniaux/pcre2-10.32/pcre2_intmodedep.h b/test/monniaux/pcre2-10.32/pcre2_intmodedep.h
new file mode 100644
index 00000000..62626d0a
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_intmodedep.h
@@ -0,0 +1,918 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains mode-dependent macro and structure definitions. The
+file is #included by pcre2_internal.h if PCRE2_CODE_UNIT_WIDTH is defined.
+These mode-dependent items are kept in a separate file so that they can also be
+#included multiple times for different code unit widths by pcre2test in order
+to have access to the hidden structures at all supported widths.
+
+Some of the mode-dependent macros are required at different widths for
+different parts of the pcre2test code (in particular, the included
+pcre_printint.c file). We undefine them here so that they can be re-defined for
+multiple inclusions. Not all of these are used in pcre2test, but it's easier
+just to undefine them all. */
+
+#undef ACROSSCHAR
+#undef BACKCHAR
+#undef BYTES2CU
+#undef CHMAX_255
+#undef CU2BYTES
+#undef FORWARDCHAR
+#undef FORWARDCHARTEST
+#undef GET
+#undef GET2
+#undef GETCHAR
+#undef GETCHARINC
+#undef GETCHARINCTEST
+#undef GETCHARLEN
+#undef GETCHARLENTEST
+#undef GETCHARTEST
+#undef GET_EXTRALEN
+#undef HAS_EXTRALEN
+#undef IMM2_SIZE
+#undef MAX_255
+#undef MAX_MARK
+#undef MAX_PATTERN_SIZE
+#undef MAX_UTF_SINGLE_CU
+#undef NOT_FIRSTCU
+#undef PUT
+#undef PUT2
+#undef PUT2INC
+#undef PUTCHAR
+#undef PUTINC
+#undef TABLE_GET
+
+
+
+/* -------------------------- MACROS ----------------------------- */
+
+/* PCRE keeps offsets in its compiled code as at least 16-bit quantities
+(always stored in big-endian order in 8-bit mode) by default. These are used,
+for example, to link from the start of a subpattern to its alternatives and its
+end. The use of 16 bits per offset limits the size of an 8-bit compiled regex
+to around 64K, which is big enough for almost everybody. However, I received a
+request for an even bigger limit. For this reason, and also to make the code
+easier to maintain, the storing and loading of offsets from the compiled code
+unit string is now handled by the macros that are defined here.
+
+The macros are controlled by the value of LINK_SIZE. This defaults to 2, but
+values of 3 or 4 are also supported. */
+
+/* ------------------- 8-bit support ------------------ */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+#if LINK_SIZE == 2
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 8)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
+#define MAX_PATTERN_SIZE (1 << 16)
+
+#elif LINK_SIZE == 3
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 16)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) >> 8)), \
+ (a[(n)+2] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 16) | ((a)[(n)+1] << 8) | (a)[(n)+2])
+#define MAX_PATTERN_SIZE (1 << 24)
+
+#elif LINK_SIZE == 4
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 24)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) >> 16)), \
+ (a[(n)+2] = (PCRE2_UCHAR)((d) >> 8)), \
+ (a[(n)+3] = (PCRE2_UCHAR)((d) & 255))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 24) | ((a)[(n)+1] << 16) | ((a)[(n)+2] << 8) | (a)[(n)+3])
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+#else
+#error LINK_SIZE must be 2, 3, or 4
+#endif
+
+
+/* ------------------- 16-bit support ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+#if LINK_SIZE == 2
+#undef LINK_SIZE
+#define LINK_SIZE 1
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)(d))
+#define GET(a,n) \
+ (a[n])
+#define MAX_PATTERN_SIZE (1 << 16)
+
+#elif LINK_SIZE == 3 || LINK_SIZE == 4
+#undef LINK_SIZE
+#define LINK_SIZE 2
+#define PUT(a,n,d) \
+ (a[n] = (PCRE2_UCHAR)((d) >> 16)), \
+ (a[(n)+1] = (PCRE2_UCHAR)((d) & 65535))
+#define GET(a,n) \
+ (unsigned int)(((a)[n] << 16) | (a)[(n)+1])
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+#else
+#error LINK_SIZE must be 2, 3, or 4
+#endif
+
+
+/* ------------------- 32-bit support ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#undef LINK_SIZE
+#define LINK_SIZE 1
+#define PUT(a,n,d) \
+ (a[n] = (d))
+#define GET(a,n) \
+ (a[n])
+#define MAX_PATTERN_SIZE (1 << 30) /* Keep it positive */
+
+#else
+#error Unsupported compiling mode
+#endif
+
+
+/* --------------- Other mode-specific macros ----------------- */
+
+/* PCRE uses some other (at least) 16-bit quantities that do not change when
+the size of offsets changes. There are used for repeat counts and for other
+things such as capturing parenthesis numbers in back references.
+
+Define the number of code units required to hold a 16-bit count/offset, and
+macros to load and store such a value. For reasons that I do not understand,
+the expression in the 8-bit GET2 macro is treated by gcc as a signed
+expression, even when a is declared as unsigned. It seems that any kind of
+arithmetic results in a signed value. Hence the cast. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define IMM2_SIZE 2
+#define GET2(a,n) (unsigned int)(((a)[n] << 8) | (a)[(n)+1])
+#define PUT2(a,n,d) a[n] = (d) >> 8, a[(n)+1] = (d) & 255
+
+#else /* Code units are 16 or 32 bits */
+#define IMM2_SIZE 1
+#define GET2(a,n) a[n]
+#define PUT2(a,n,d) a[n] = d
+#endif
+
+/* Other macros that are different for 8-bit mode. The MAX_255 macro checks
+whether its argument, which is assumed to be one code unit, is less than 256.
+The CHMAX_255 macro does not assume one code unit. The maximum length of a MARK
+name must fit in one code unit; currently it is set to 255 or 65535. The
+TABLE_GET macro is used to access elements of tables containing exactly 256
+items. When code points can be greater than 255, a check is needed before
+accessing these tables. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MAX_255(c) TRUE
+#define MAX_MARK ((1u << 8) - 1)
+#ifdef SUPPORT_UNICODE
+#define SUPPORT_WIDE_CHARS
+#define CHMAX_255(c) ((c) <= 255u)
+#else
+#define CHMAX_255(c) TRUE
+#endif /* SUPPORT_UNICODE */
+#define TABLE_GET(c, table, default) ((table)[c])
+
+#else /* Code units are 16 or 32 bits */
+#define CHMAX_255(c) ((c) <= 255u)
+#define MAX_255(c) ((c) <= 255u)
+#define MAX_MARK ((1u << 16) - 1)
+#define SUPPORT_WIDE_CHARS
+#define TABLE_GET(c, table, default) (MAX_255(c)? ((table)[c]):(default))
+#endif
+
+
+
+/* ----------------- Character-handling macros ----------------- */
+
+/* There is a proposed future special "UTF-21" mode, in which only the lowest
+21 bits of a 32-bit character are interpreted as UTF, with the remaining 11
+high-order bits available to the application for other uses. In preparation for
+the future implementation of this mode, there are macros that load a data item
+and, if in this special mode, mask it to 21 bits. These macros all have names
+starting with UCHAR21. In all other modes, including the normal 32-bit
+library, the macros all have the same simple definitions. When the new mode is
+implemented, it is expected that these definitions will be varied appropriately
+using #ifdef when compiling the library that supports the special mode. */
+
+#define UCHAR21(eptr) (*(eptr))
+#define UCHAR21TEST(eptr) (*(eptr))
+#define UCHAR21INC(eptr) (*(eptr)++)
+#define UCHAR21INCTEST(eptr) (*(eptr)++)
+
+/* When UTF encoding is being used, a character is no longer just a single
+byte in 8-bit mode or a single short in 16-bit mode. The macros for character
+handling generate simple sequences when used in the basic mode, and more
+complicated ones for UTF characters. GETCHARLENTEST and other macros are not
+used when UTF is not supported. To make sure they can never even appear when
+UTF support is omitted, we don't even define them. */
+
+#ifndef SUPPORT_UNICODE
+
+/* #define MAX_UTF_SINGLE_CU */
+/* #define HAS_EXTRALEN(c) */
+/* #define GET_EXTRALEN(c) */
+/* #define NOT_FIRSTCU(c) */
+#define GETCHAR(c, eptr) c = *eptr;
+#define GETCHARTEST(c, eptr) c = *eptr;
+#define GETCHARINC(c, eptr) c = *eptr++;
+#define GETCHARINCTEST(c, eptr) c = *eptr++;
+#define GETCHARLEN(c, eptr, len) c = *eptr;
+#define PUTCHAR(c, p) (*p = c, 1)
+/* #define GETCHARLENTEST(c, eptr, len) */
+/* #define BACKCHAR(eptr) */
+/* #define FORWARDCHAR(eptr) */
+/* #define FORWARCCHARTEST(eptr,end) */
+/* #define ACROSSCHAR(condition, eptr, action) */
+
+#else /* SUPPORT_UNICODE */
+
+/* ------------------- 8-bit support ------------------ */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MAYBE_UTF_MULTI /* UTF chars may use multiple code units */
+
+/* The largest UTF code point that can be encoded as a single code unit. */
+
+#define MAX_UTF_SINGLE_CU 127
+
+/* Tests whether the code point needs extra characters to decode. */
+
+#define HAS_EXTRALEN(c) HASUTF8EXTRALEN(c)
+
+/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
+Otherwise it has an undefined behaviour. */
+
+#define GET_EXTRALEN(c) (PRIV(utf8_table4)[(c) & 0x3fu])
+
+/* Returns TRUE, if the given value is not the first code unit of a UTF
+sequence. */
+
+#define NOT_FIRSTCU(c) (((c) & 0xc0u) == 0x80u)
+
+/* Get the next UTF-8 character, not advancing the pointer. This is called when
+we know we are in UTF-8 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *eptr; \
+ if (c >= 0xc0u) GETUTF8(c, eptr);
+
+/* Get the next UTF-8 character, testing for UTF-8 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+ c = *eptr; \
+ if (utf && c >= 0xc0u) GETUTF8(c, eptr);
+
+/* Get the next UTF-8 character, advancing the pointer. This is called when we
+know we are in UTF-8 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *eptr++; \
+ if (c >= 0xc0u) GETUTF8INC(c, eptr);
+
+/* Get the next character, testing for UTF-8 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-8 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *eptr++; \
+ if (utf && c >= 0xc0u) GETUTF8INC(c, eptr);
+
+/* Get the next UTF-8 character, not advancing the pointer, incrementing length
+if there are extra bytes. This is called when we know we are in UTF-8 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ c = *eptr; \
+ if (c >= 0xc0u) GETUTF8LEN(c, eptr, len);
+
+/* Get the next UTF-8 character, testing for UTF-8 mode, not advancing the
+pointer, incrementing length if there are extra bytes. This is called when we
+do not know if we are in UTF-8 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+ c = *eptr; \
+ if (utf && c >= 0xc0u) GETUTF8LEN(c, eptr, len);
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-8 mode - we don't put a test within the macro
+because almost all calls are already within a block of UTF-8 only code. */
+
+#define BACKCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr--
+
+/* Same as above, just in the other direction. */
+#define FORWARDCHAR(eptr) while((*eptr & 0xc0u) == 0x80u) eptr++
+#define FORWARDCHARTEST(eptr,end) while(eptr < end && (*eptr & 0xc0u) == 0x80u) eptr++
+
+/* Same as above, but it allows a fully customizable form. */
+#define ACROSSCHAR(condition, eptr, action) \
+ while((condition) && ((*eptr) & 0xc0u) == 0x80u) action
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \
+ PRIV(ord2utf)(c,p) : (*p = c, 1))
+
+
+/* ------------------- 16-bit support ------------------ */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define MAYBE_UTF_MULTI /* UTF chars may use multiple code units */
+
+/* The largest UTF code point that can be encoded as a single code unit. */
+
+#define MAX_UTF_SINGLE_CU 65535
+
+/* Tests whether the code point needs extra characters to decode. */
+
+#define HAS_EXTRALEN(c) (((c) & 0xfc00u) == 0xd800u)
+
+/* Returns with the additional number of characters if IS_MULTICHAR(c) is TRUE.
+Otherwise it has an undefined behaviour. */
+
+#define GET_EXTRALEN(c) 1
+
+/* Returns TRUE, if the given value is not the first code unit of a UTF
+sequence. */
+
+#define NOT_FIRSTCU(c) (((c) & 0xfc00u) == 0xdc00u)
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, not
+advancing the pointer. */
+
+#define GETUTF16(c, eptr) \
+ { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; }
+
+/* Get the next UTF-16 character, not advancing the pointer. This is called when
+we know we are in UTF-16 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *eptr; \
+ if ((c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr);
+
+/* Get the next UTF-16 character, testing for UTF-16 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+ c = *eptr; \
+ if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16(c, eptr);
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, advancing
+the pointer. */
+
+#define GETUTF16INC(c, eptr) \
+ { c = (((c & 0x3ffu) << 10) | (*eptr++ & 0x3ffu)) + 0x10000u; }
+
+/* Get the next UTF-16 character, advancing the pointer. This is called when we
+know we are in UTF-16 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *eptr++; \
+ if ((c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr);
+
+/* Get the next character, testing for UTF-16 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-16 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *eptr++; \
+ if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16INC(c, eptr);
+
+/* Base macro to pick up the low surrogate of a UTF-16 character, not
+advancing the pointer, incrementing the length. */
+
+#define GETUTF16LEN(c, eptr, len) \
+ { c = (((c & 0x3ffu) << 10) | (eptr[1] & 0x3ffu)) + 0x10000u; len++; }
+
+/* Get the next UTF-16 character, not advancing the pointer, incrementing
+length if there is a low surrogate. This is called when we know we are in
+UTF-16 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ c = *eptr; \
+ if ((c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len);
+
+/* Get the next UTF-816character, testing for UTF-16 mode, not advancing the
+pointer, incrementing length if there is a low surrogate. This is called when
+we do not know if we are in UTF-16 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+ c = *eptr; \
+ if (utf && (c & 0xfc00u) == 0xd800u) GETUTF16LEN(c, eptr, len);
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-16 mode - we don't put a test within the
+macro because almost all calls are already within a block of UTF-16 only
+code. */
+
+#define BACKCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr--
+
+/* Same as above, just in the other direction. */
+#define FORWARDCHAR(eptr) if ((*eptr & 0xfc00u) == 0xdc00u) eptr++
+#define FORWARDCHARTEST(eptr,end) if (eptr < end && (*eptr & 0xfc00u) == 0xdc00u) eptr++
+
+/* Same as above, but it allows a fully customizable form. */
+#define ACROSSCHAR(condition, eptr, action) \
+ if ((condition) && ((*eptr) & 0xfc00u) == 0xdc00u) action
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) ((utf && c > MAX_UTF_SINGLE_CU)? \
+ PRIV(ord2utf)(c,p) : (*p = c, 1))
+
+
+/* ------------------- 32-bit support ------------------ */
+
+#else
+
+/* These are trivial for the 32-bit library, since all UTF-32 characters fit
+into one PCRE2_UCHAR unit. */
+
+#define MAX_UTF_SINGLE_CU (0x10ffffu)
+#define HAS_EXTRALEN(c) (0)
+#define GET_EXTRALEN(c) (0)
+#define NOT_FIRSTCU(c) (0)
+
+/* Get the next UTF-32 character, not advancing the pointer. This is called when
+we know we are in UTF-32 mode. */
+
+#define GETCHAR(c, eptr) \
+ c = *(eptr);
+
+/* Get the next UTF-32 character, testing for UTF-32 mode, and not advancing the
+pointer. */
+
+#define GETCHARTEST(c, eptr) \
+ c = *(eptr);
+
+/* Get the next UTF-32 character, advancing the pointer. This is called when we
+know we are in UTF-32 mode. */
+
+#define GETCHARINC(c, eptr) \
+ c = *((eptr)++);
+
+/* Get the next character, testing for UTF-32 mode, and advancing the pointer.
+This is called when we don't know if we are in UTF-32 mode. */
+
+#define GETCHARINCTEST(c, eptr) \
+ c = *((eptr)++);
+
+/* Get the next UTF-32 character, not advancing the pointer, not incrementing
+length (since all UTF-32 is of length 1). This is called when we know we are in
+UTF-32 mode. */
+
+#define GETCHARLEN(c, eptr, len) \
+ GETCHAR(c, eptr)
+
+/* Get the next UTF-32character, testing for UTF-32 mode, not advancing the
+pointer, not incrementing the length (since all UTF-32 is of length 1).
+This is called when we do not know if we are in UTF-32 mode. */
+
+#define GETCHARLENTEST(c, eptr, len) \
+ GETCHARTEST(c, eptr)
+
+/* If the pointer is not at the start of a character, move it back until
+it is. This is called only in UTF-32 mode - we don't put a test within the
+macro because almost all calls are already within a block of UTF-32 only
+code.
+
+These are all no-ops since all UTF-32 characters fit into one pcre_uchar. */
+
+#define BACKCHAR(eptr) do { } while (0)
+
+/* Same as above, just in the other direction. */
+
+#define FORWARDCHAR(eptr) do { } while (0)
+#define FORWARDCHARTEST(eptr,end) do { } while (0)
+
+/* Same as above, but it allows a fully customizable form. */
+
+#define ACROSSCHAR(condition, eptr, action) do { } while (0)
+
+/* Deposit a character into memory, returning the number of code units. */
+
+#define PUTCHAR(c, p) (*p = c, 1)
+
+#endif /* UTF-32 character handling */
+#endif /* SUPPORT_UNICODE */
+
+
+/* Mode-dependent macros that have the same definition in all modes. */
+
+#define CU2BYTES(x) ((x)*((PCRE2_CODE_UNIT_WIDTH/8)))
+#define BYTES2CU(x) ((x)/((PCRE2_CODE_UNIT_WIDTH/8)))
+#define PUTINC(a,n,d) PUT(a,n,d), a += LINK_SIZE
+#define PUT2INC(a,n,d) PUT2(a,n,d), a += IMM2_SIZE
+
+
+/* ----------------------- HIDDEN STRUCTURES ----------------------------- */
+
+/* NOTE: All these structures *must* start with a pcre2_memctl structure. The
+code that uses them is simpler because it assumes this. */
+
+/* The real general context structure. At present it holds only data for custom
+memory control. */
+
+typedef struct pcre2_real_general_context {
+ pcre2_memctl memctl;
+} pcre2_real_general_context;
+
+/* The real compile context structure */
+
+typedef struct pcre2_real_compile_context {
+ pcre2_memctl memctl;
+ int (*stack_guard)(uint32_t, void *);
+ void *stack_guard_data;
+ const uint8_t *tables;
+ PCRE2_SIZE max_pattern_length;
+ uint16_t bsr_convention;
+ uint16_t newline_convention;
+ uint32_t parens_nest_limit;
+ uint32_t extra_options;
+} pcre2_real_compile_context;
+
+/* The real match context structure. */
+
+typedef struct pcre2_real_match_context {
+ pcre2_memctl memctl;
+#ifdef SUPPORT_JIT
+ pcre2_jit_callback jit_callback;
+ void *jit_callback_data;
+#endif
+ int (*callout)(pcre2_callout_block *, void *);
+ void *callout_data;
+ PCRE2_SIZE offset_limit;
+ uint32_t heap_limit;
+ uint32_t match_limit;
+ uint32_t depth_limit;
+} pcre2_real_match_context;
+
+/* The real convert context structure. */
+
+typedef struct pcre2_real_convert_context {
+ pcre2_memctl memctl;
+ uint32_t glob_separator;
+ uint32_t glob_escape;
+} pcre2_real_convert_context;
+
+/* The real compiled code structure. The type for the blocksize field is
+defined specially because it is required in pcre2_serialize_decode() when
+copying the size from possibly unaligned memory into a variable of the same
+type. Use a macro rather than a typedef to avoid compiler warnings when this
+file is included multiple times by pcre2test. LOOKBEHIND_MAX specifies the
+largest lookbehind that is supported. (OP_REVERSE in a pattern has a 16-bit
+argument in 8-bit and 16-bit modes, so we need no more than a 16-bit field
+here.) */
+
+#undef CODE_BLOCKSIZE_TYPE
+#define CODE_BLOCKSIZE_TYPE size_t
+
+#undef LOOKBEHIND_MAX
+#define LOOKBEHIND_MAX UINT16_MAX
+
+typedef struct pcre2_real_code {
+ pcre2_memctl memctl; /* Memory control fields */
+ const uint8_t *tables; /* The character tables */
+ void *executable_jit; /* Pointer to JIT code */
+ uint8_t start_bitmap[32]; /* Bitmap for starting code unit < 256 */
+ CODE_BLOCKSIZE_TYPE blocksize; /* Total (bytes) that was malloc-ed */
+ uint32_t magic_number; /* Paranoid and endianness check */
+ uint32_t compile_options; /* Options passed to pcre2_compile() */
+ uint32_t overall_options; /* Options after processing the pattern */
+ uint32_t extra_options; /* Taken from compile_context */
+ uint32_t flags; /* Various state flags */
+ uint32_t limit_heap; /* Limit set in the pattern */
+ uint32_t limit_match; /* Limit set in the pattern */
+ uint32_t limit_depth; /* Limit set in the pattern */
+ uint32_t first_codeunit; /* Starting code unit */
+ uint32_t last_codeunit; /* This codeunit must be seen */
+ uint16_t bsr_convention; /* What \R matches */
+ uint16_t newline_convention; /* What is a newline? */
+ uint16_t max_lookbehind; /* Longest lookbehind (characters) */
+ uint16_t minlength; /* Minimum length of match */
+ uint16_t top_bracket; /* Highest numbered group */
+ uint16_t top_backref; /* Highest numbered back reference */
+ uint16_t name_entry_size; /* Size (code units) of table entries */
+ uint16_t name_count; /* Number of name entries in the table */
+} pcre2_real_code;
+
+/* The real match data structure. Define ovector as large as it can ever
+actually be so that array bound checkers don't grumble. Memory for this
+structure is obtained by calling pcre2_match_data_create(), which sets the size
+as the offset of ovector plus a pair of elements for each capturable string, so
+the size varies from call to call. As the maximum number of capturing
+subpatterns is 65535 we must allow for 65536 strings to include the overall
+match. (See also the heapframe structure below.) */
+
+typedef struct pcre2_real_match_data {
+ pcre2_memctl memctl;
+ const pcre2_real_code *code; /* The pattern used for the match */
+ PCRE2_SPTR subject; /* The subject that was matched */
+ PCRE2_SPTR mark; /* Pointer to last mark */
+ PCRE2_SIZE leftchar; /* Offset to leftmost code unit */
+ PCRE2_SIZE rightchar; /* Offset to rightmost code unit */
+ PCRE2_SIZE startchar; /* Offset to starting code unit */
+ uint16_t matchedby; /* Type of match (normal, JIT, DFA) */
+ uint16_t oveccount; /* Number of pairs */
+ int rc; /* The return code from the match */
+ PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
+} pcre2_real_match_data;
+
+
+/* ----------------------- PRIVATE STRUCTURES ----------------------------- */
+
+/* These structures are not needed for pcre2test. */
+
+#ifndef PCRE2_PCRE2TEST
+
+/* Structures for checking for mutual recursion when scanning compiled or
+parsed code. */
+
+typedef struct recurse_check {
+ struct recurse_check *prev;
+ PCRE2_SPTR group;
+} recurse_check;
+
+typedef struct parsed_recurse_check {
+ struct parsed_recurse_check *prev;
+ uint32_t *groupptr;
+} parsed_recurse_check;
+
+/* Structure for building a cache when filling in recursion offsets. */
+
+typedef struct recurse_cache {
+ PCRE2_SPTR group;
+ int groupnumber;
+} recurse_cache;
+
+/* Structure for maintaining a chain of pointers to the currently incomplete
+branches, for testing for left recursion while compiling. */
+
+typedef struct branch_chain {
+ struct branch_chain *outer;
+ PCRE2_UCHAR *current_branch;
+} branch_chain;
+
+/* Structure for building a list of named groups during the first pass of
+compiling. */
+
+typedef struct named_group {
+ PCRE2_SPTR name; /* Points to the name in the pattern */
+ uint32_t number; /* Group number */
+ uint16_t length; /* Length of the name */
+ uint16_t isdup; /* TRUE if a duplicate */
+} named_group;
+
+/* Structure for passing "static" information around between the functions
+doing the compiling, so that they are thread-safe. */
+
+typedef struct compile_block {
+ pcre2_real_compile_context *cx; /* Points to the compile context */
+ const uint8_t *lcc; /* Points to lower casing table */
+ const uint8_t *fcc; /* Points to case-flipping table */
+ const uint8_t *cbits; /* Points to character type table */
+ const uint8_t *ctypes; /* Points to table of type maps */
+ PCRE2_SPTR start_workspace; /* The start of working space */
+ PCRE2_SPTR start_code; /* The start of the compiled code */
+ PCRE2_SPTR start_pattern; /* The start of the pattern */
+ PCRE2_SPTR end_pattern; /* The end of the pattern */
+ PCRE2_UCHAR *name_table; /* The name/number table */
+ PCRE2_SIZE workspace_size; /* Size of workspace */
+ PCRE2_SIZE small_ref_offset[10]; /* Offsets for \1 to \9 */
+ PCRE2_SIZE erroroffset; /* Offset of error in pattern */
+ uint16_t names_found; /* Number of entries so far */
+ uint16_t name_entry_size; /* Size of each entry */
+ uint16_t parens_depth; /* Depth of nested parentheses */
+ uint16_t assert_depth; /* Depth of nested assertions */
+ open_capitem *open_caps; /* Chain of open capture items */
+ named_group *named_groups; /* Points to vector in pre-compile */
+ uint32_t named_group_list_size; /* Number of entries in the list */
+ uint32_t external_options; /* External (initial) options */
+ uint32_t external_flags; /* External flag bits to be set */
+ uint32_t bracount; /* Count of capturing parentheses */
+ uint32_t lastcapture; /* Last capture encountered */
+ uint32_t *parsed_pattern; /* Parsed pattern buffer */
+ uint32_t *parsed_pattern_end; /* Parsed pattern should not get here */
+ uint32_t *groupinfo; /* Group info vector */
+ uint32_t top_backref; /* Maximum back reference */
+ uint32_t backref_map; /* Bitmap of low back refs */
+ uint32_t nltype; /* Newline type */
+ uint32_t nllen; /* Newline string length */
+ uint32_t class_range_start; /* Overall class range start */
+ uint32_t class_range_end; /* Overall class range end */
+ PCRE2_UCHAR nl[4]; /* Newline string when fixed length */
+ int max_lookbehind; /* Maximum lookbehind (characters) */
+ int req_varyopt; /* "After variable item" flag for reqbyte */
+ BOOL had_accept; /* (*ACCEPT) encountered */
+ BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
+ BOOL had_recurse; /* Had a recursion or subroutine call */
+ BOOL dupnames; /* Duplicate names exist */
+} compile_block;
+
+/* Structure for keeping the properties of the in-memory stack used
+by the JIT matcher. */
+
+typedef struct pcre2_real_jit_stack {
+ pcre2_memctl memctl;
+ void* stack;
+} pcre2_real_jit_stack;
+
+/* Structure for items in a linked list that represents an explicit recursive
+call within the pattern when running pcre_dfa_match(). */
+
+typedef struct dfa_recursion_info {
+ struct dfa_recursion_info *prevrec;
+ PCRE2_SPTR subject_position;
+ uint32_t group_num;
+} dfa_recursion_info;
+
+/* Structure for "stack" frames that are used for remembering backtracking
+positions during matching. As these are used in a vector, with the ovector item
+being extended, the size of the structure must be a multiple of PCRE2_SIZE. The
+only way to check this at compile time is to force an error by generating an
+array with a negative size. By putting this in a typedef (which is never used),
+we don't generate any code when all is well. */
+
+typedef struct heapframe {
+
+ /* The first set of fields are variables that have to be preserved over calls
+ to RRMATCH(), but which do not need to be copied to new frames. */
+
+ PCRE2_SPTR ecode; /* The current position in the pattern */
+ PCRE2_SPTR temp_sptr[2]; /* Used for short-term PCRE_SPTR values */
+ PCRE2_SIZE length; /* Used for character, string, or code lengths */
+ PCRE2_SIZE back_frame; /* Amount to subtract on RRETURN */
+ PCRE2_SIZE temp_size; /* Used for short-term PCRE2_SIZE values */
+ uint32_t rdepth; /* "Recursion" depth */
+ uint32_t group_frame_type; /* Type information for group frames */
+ uint32_t temp_32[4]; /* Used for short-term 32-bit or BOOL values */
+ uint8_t return_id; /* Where to go on in internal "return" */
+ uint8_t op; /* Processing opcode */
+
+ /* At this point, the structure is 16-bit aligned. On most architectures
+ the alignment requirement for a pointer will ensure that the eptr field below
+ is 32-bit or 64-bit aligned. However, on m68k it is fine to have a pointer
+ that is 16-bit aligned. We must therefore ensure that what comes between here
+ and eptr is an odd multiple of 16 bits so as to get back into 32-bit
+ alignment. This happens naturally when PCRE2_UCHAR is 8 bits wide, but needs
+ fudges in the other cases. In the 32-bit case the padding comes first so that
+ the occu field itself is 32-bit aligned. Without the padding, this structure
+ is no longer a multiple of PCRE2_SIZE on m68k, and the check below fails. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ PCRE2_UCHAR occu[6]; /* Used for other case code units */
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ PCRE2_UCHAR occu[2]; /* Used for other case code units */
+ uint8_t unused[2]; /* Ensure 32-bit alignment (see above) */
+#else
+ uint8_t unused[2]; /* Ensure 32-bit alignment (see above) */
+ PCRE2_UCHAR occu[1]; /* Used for other case code units */
+#endif
+
+ /* The rest have to be copied from the previous frame whenever a new frame
+ becomes current. The final field is specified as a large vector so that
+ runtime array bound checks don't catch references to it. However, for any
+ specific call to pcre2_match() the memory allocated for each frame structure
+ allows for exactly the right size ovector for the number of capturing
+ parentheses. (See also the comment for pcre2_real_match_data above.) */
+
+ PCRE2_SPTR eptr; /* MUST BE FIRST */
+ PCRE2_SPTR start_match; /* Can be adjusted by \K */
+ PCRE2_SPTR mark; /* Most recent mark on the success path */
+ uint32_t current_recurse; /* Current (deepest) recursion number */
+ uint32_t capture_last; /* Most recent capture */
+ PCRE2_SIZE last_group_offset; /* Saved offset to most recent group frame */
+ PCRE2_SIZE offset_top; /* Offset after highest capture */
+ PCRE2_SIZE ovector[131072]; /* Must be last in the structure */
+} heapframe;
+
+/* This typedef is a check that the size of the heapframe structure is a
+multiple of PCRE2_SIZE. See various comments above. */
+
+typedef char check_heapframe_size[
+ ((sizeof(heapframe) % sizeof(PCRE2_SIZE)) == 0)? (+1):(-1)];
+
+/* Structure for passing "static" information around between the functions
+doing traditional NFA matching (pcre2_match() and friends). */
+
+typedef struct match_block {
+ pcre2_memctl memctl; /* For general use */
+ PCRE2_SIZE frame_vector_size; /* Size of a backtracking frame */
+ heapframe *match_frames; /* Points to vector of frames */
+ heapframe *match_frames_top; /* Points after the end of the vector */
+ heapframe *stack_frames; /* The original vector on the stack */
+ PCRE2_SIZE heap_limit; /* As it says */
+ uint32_t match_limit; /* As it says */
+ uint32_t match_limit_depth; /* As it says */
+ uint32_t match_call_count; /* Number of times a new frame is created */
+ BOOL hitend; /* Hit the end of the subject at some point */
+ BOOL hasthen; /* Pattern contains (*THEN) */
+ const uint8_t *lcc; /* Points to lower casing table */
+ const uint8_t *fcc; /* Points to case-flipping table */
+ const uint8_t *ctypes; /* Points to table of type maps */
+ PCRE2_SIZE start_offset; /* The start offset value */
+ PCRE2_SIZE end_offset_top; /* Highwater mark at end of match */
+ uint16_t partial; /* PARTIAL options */
+ uint16_t bsr_convention; /* \R interpretation */
+ uint16_t name_count; /* Number of names in name table */
+ uint16_t name_entry_size; /* Size of entry in names table */
+ PCRE2_SPTR name_table; /* Table of group names */
+ PCRE2_SPTR start_code; /* For use when recursing */
+ PCRE2_SPTR start_subject; /* Start of the subject string */
+ PCRE2_SPTR end_subject; /* End of the subject string */
+ PCRE2_SPTR end_match_ptr; /* Subject position at end match */
+ PCRE2_SPTR start_used_ptr; /* Earliest consulted character */
+ PCRE2_SPTR last_used_ptr; /* Latest consulted character */
+ PCRE2_SPTR mark; /* Mark pointer to pass back on success */
+ PCRE2_SPTR nomatch_mark; /* Mark pointer to pass back on failure */
+ PCRE2_SPTR verb_ecode_ptr; /* For passing back info */
+ PCRE2_SPTR verb_skip_ptr; /* For passing back a (*SKIP) name */
+ uint32_t verb_current_recurse; /* Current recurse when (*VERB) happens */
+ uint32_t moptions; /* Match options */
+ uint32_t poptions; /* Pattern options */
+ uint32_t skip_arg_count; /* For counting SKIP_ARGs */
+ uint32_t ignore_skip_arg; /* For re-run when SKIP arg name not found */
+ uint32_t nltype; /* Newline type */
+ uint32_t nllen; /* Newline string length */
+ PCRE2_UCHAR nl[4]; /* Newline string when fixed */
+ pcre2_callout_block *cb; /* Points to a callout block */
+ void *callout_data; /* To pass back to callouts */
+ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */
+} match_block;
+
+/* A similar structure is used for the same purpose by the DFA matching
+functions. */
+
+typedef struct dfa_match_block {
+ pcre2_memctl memctl; /* For general use */
+ PCRE2_SPTR start_code; /* Start of the compiled pattern */
+ PCRE2_SPTR start_subject ; /* Start of the subject string */
+ PCRE2_SPTR end_subject; /* End of subject string */
+ PCRE2_SPTR start_used_ptr; /* Earliest consulted character */
+ PCRE2_SPTR last_used_ptr; /* Latest consulted character */
+ const uint8_t *tables; /* Character tables */
+ PCRE2_SIZE start_offset; /* The start offset value */
+ PCRE2_SIZE heap_limit; /* As it says */
+ PCRE2_SIZE heap_used; /* As it says */
+ uint32_t match_limit; /* As it says */
+ uint32_t match_limit_depth; /* As it says */
+ uint32_t match_call_count; /* Number of calls of internal function */
+ uint32_t moptions; /* Match options */
+ uint32_t poptions; /* Pattern options */
+ uint32_t nltype; /* Newline type */
+ uint32_t nllen; /* Newline string length */
+ PCRE2_UCHAR nl[4]; /* Newline string when fixed */
+ uint16_t bsr_convention; /* \R interpretation */
+ pcre2_callout_block *cb; /* Points to a callout block */
+ void *callout_data; /* To pass back to callouts */
+ int (*callout)(pcre2_callout_block *,void *); /* Callout function or NULL */
+ dfa_recursion_info *recursive; /* Linked list of recursion data */
+} dfa_match_block;
+
+#endif /* PCRE2_PCRE2TEST */
+
+/* End of pcre2_intmodedep.h */
diff --git a/test/monniaux/pcre2-10.32/pcre2_jit_compile.c b/test/monniaux/pcre2-10.32/pcre2_jit_compile.c
new file mode 100644
index 00000000..32e985b7
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_jit_compile.c
@@ -0,0 +1,12708 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#ifdef SUPPORT_JIT
+
+/* All-in-one: Since we use the JIT compiler only from here,
+we just include it. This way we don't need to touch the build
+system files. */
+
+#define SLJIT_CONFIG_AUTO 1
+#define SLJIT_CONFIG_STATIC 1
+#define SLJIT_VERBOSE 0
+
+#ifdef PCRE2_DEBUG
+#define SLJIT_DEBUG 1
+#else
+#define SLJIT_DEBUG 0
+#endif
+
+#define SLJIT_MALLOC(size, allocator_data) pcre2_jit_malloc(size, allocator_data)
+#define SLJIT_FREE(ptr, allocator_data) pcre2_jit_free(ptr, allocator_data)
+
+static void * pcre2_jit_malloc(size_t size, void *allocator_data)
+{
+pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data);
+return allocator->malloc(size, allocator->memory_data);
+}
+
+static void pcre2_jit_free(void *ptr, void *allocator_data)
+{
+pcre2_memctl *allocator = ((pcre2_memctl*)allocator_data);
+allocator->free(ptr, allocator->memory_data);
+}
+
+#include "sljit/sljitLir.c"
+
+#if defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED
+#error Unsupported architecture
+#endif
+
+/* Defines for debugging purposes. */
+
+/* 1 - Use unoptimized capturing brackets.
+ 2 - Enable capture_last_ptr (includes option 1). */
+/* #define DEBUG_FORCE_UNOPTIMIZED_CBRAS 2 */
+
+/* 1 - Always have a control head. */
+/* #define DEBUG_FORCE_CONTROL_HEAD 1 */
+
+/* Allocate memory for the regex stack on the real machine stack.
+Fast, but limited size. */
+#define MACHINE_STACK_SIZE 32768
+
+/* Growth rate for stack allocated by the OS. Should be the multiply
+of page size. */
+#define STACK_GROWTH_RATE 8192
+
+/* Enable to check that the allocation could destroy temporaries. */
+#if defined SLJIT_DEBUG && SLJIT_DEBUG
+#define DESTROY_REGISTERS 1
+#endif
+
+/*
+Short summary about the backtracking mechanism empolyed by the jit code generator:
+
+The code generator follows the recursive nature of the PERL compatible regular
+expressions. The basic blocks of regular expressions are condition checkers
+whose execute different commands depending on the result of the condition check.
+The relationship between the operators can be horizontal (concatenation) and
+vertical (sub-expression) (See struct backtrack_common for more details).
+
+ 'ab' - 'a' and 'b' regexps are concatenated
+ 'a+' - 'a' is the sub-expression of the '+' operator
+
+The condition checkers are boolean (true/false) checkers. Machine code is generated
+for the checker itself and for the actions depending on the result of the checker.
+The 'true' case is called as the matching path (expected path), and the other is called as
+the 'backtrack' path. Branch instructions are expesive for all CPUs, so we avoid taken
+branches on the matching path.
+
+ Greedy star operator (*) :
+ Matching path: match happens.
+ Backtrack path: match failed.
+ Non-greedy star operator (*?) :
+ Matching path: no need to perform a match.
+ Backtrack path: match is required.
+
+The following example shows how the code generated for a capturing bracket
+with two alternatives. Let A, B, C, D are arbirary regular expressions, and
+we have the following regular expression:
+
+ A(B|C)D
+
+The generated code will be the following:
+
+ A matching path
+ '(' matching path (pushing arguments to the stack)
+ B matching path
+ ')' matching path (pushing arguments to the stack)
+ D matching path
+ return with successful match
+
+ D backtrack path
+ ')' backtrack path (If we arrived from "C" jump to the backtrack of "C")
+ B backtrack path
+ C expected path
+ jump to D matching path
+ C backtrack path
+ A backtrack path
+
+ Notice, that the order of backtrack code paths are the opposite of the fast
+ code paths. In this way the topmost value on the stack is always belong
+ to the current backtrack code path. The backtrack path must check
+ whether there is a next alternative. If so, it needs to jump back to
+ the matching path eventually. Otherwise it needs to clear out its own stack
+ frame and continue the execution on the backtrack code paths.
+*/
+
+/*
+Saved stack frames:
+
+Atomic blocks and asserts require reloading the values of private data
+when the backtrack mechanism performed. Because of OP_RECURSE, the data
+are not necessarly known in compile time, thus we need a dynamic restore
+mechanism.
+
+The stack frames are stored in a chain list, and have the following format:
+([ capturing bracket offset ][ start value ][ end value ])+ ... [ 0 ] [ previous head ]
+
+Thus we can restore the private data to a particular point in the stack.
+*/
+
+typedef struct jit_arguments {
+ /* Pointers first. */
+ struct sljit_stack *stack;
+ PCRE2_SPTR str;
+ PCRE2_SPTR begin;
+ PCRE2_SPTR end;
+ pcre2_match_data *match_data;
+ PCRE2_SPTR startchar_ptr;
+ PCRE2_UCHAR *mark_ptr;
+ int (*callout)(pcre2_callout_block *, void *);
+ void *callout_data;
+ /* Everything else after. */
+ sljit_uw offset_limit;
+ sljit_u32 limit_match;
+ sljit_u32 oveccount;
+ sljit_u32 options;
+} jit_arguments;
+
+#define JIT_NUMBER_OF_COMPILE_MODES 3
+
+typedef struct executable_functions {
+ void *executable_funcs[JIT_NUMBER_OF_COMPILE_MODES];
+ void *read_only_data_heads[JIT_NUMBER_OF_COMPILE_MODES];
+ sljit_uw executable_sizes[JIT_NUMBER_OF_COMPILE_MODES];
+ sljit_u32 top_bracket;
+ sljit_u32 limit_match;
+} executable_functions;
+
+typedef struct jump_list {
+ struct sljit_jump *jump;
+ struct jump_list *next;
+} jump_list;
+
+typedef struct stub_list {
+ struct sljit_jump *start;
+ struct sljit_label *quit;
+ struct stub_list *next;
+} stub_list;
+
+typedef struct label_addr_list {
+ struct sljit_label *label;
+ sljit_uw *update_addr;
+ struct label_addr_list *next;
+} label_addr_list;
+
+enum frame_types {
+ no_frame = -1,
+ no_stack = -2
+};
+
+enum control_types {
+ type_mark = 0,
+ type_then_trap = 1
+};
+
+typedef int (SLJIT_FUNC *jit_function)(jit_arguments *args);
+
+/* The following structure is the key data type for the recursive
+code generator. It is allocated by compile_matchingpath, and contains
+the arguments for compile_backtrackingpath. Must be the first member
+of its descendants. */
+typedef struct backtrack_common {
+ /* Concatenation stack. */
+ struct backtrack_common *prev;
+ jump_list *nextbacktracks;
+ /* Internal stack (for component operators). */
+ struct backtrack_common *top;
+ jump_list *topbacktracks;
+ /* Opcode pointer. */
+ PCRE2_SPTR cc;
+} backtrack_common;
+
+typedef struct assert_backtrack {
+ backtrack_common common;
+ jump_list *condfailed;
+ /* Less than 0 if a frame is not needed. */
+ int framesize;
+ /* Points to our private memory word on the stack. */
+ int private_data_ptr;
+ /* For iterators. */
+ struct sljit_label *matchingpath;
+} assert_backtrack;
+
+typedef struct bracket_backtrack {
+ backtrack_common common;
+ /* Where to coninue if an alternative is successfully matched. */
+ struct sljit_label *alternative_matchingpath;
+ /* For rmin and rmax iterators. */
+ struct sljit_label *recursive_matchingpath;
+ /* For greedy ? operator. */
+ struct sljit_label *zero_matchingpath;
+ /* Contains the branches of a failed condition. */
+ union {
+ /* Both for OP_COND, OP_SCOND. */
+ jump_list *condfailed;
+ assert_backtrack *assert;
+ /* For OP_ONCE. Less than 0 if not needed. */
+ int framesize;
+ } u;
+ /* Points to our private memory word on the stack. */
+ int private_data_ptr;
+} bracket_backtrack;
+
+typedef struct bracketpos_backtrack {
+ backtrack_common common;
+ /* Points to our private memory word on the stack. */
+ int private_data_ptr;
+ /* Reverting stack is needed. */
+ int framesize;
+ /* Allocated stack size. */
+ int stacksize;
+} bracketpos_backtrack;
+
+typedef struct braminzero_backtrack {
+ backtrack_common common;
+ struct sljit_label *matchingpath;
+} braminzero_backtrack;
+
+typedef struct char_iterator_backtrack {
+ backtrack_common common;
+ /* Next iteration. */
+ struct sljit_label *matchingpath;
+ union {
+ jump_list *backtracks;
+ struct {
+ unsigned int othercasebit;
+ PCRE2_UCHAR chr;
+ BOOL enabled;
+ } charpos;
+ } u;
+} char_iterator_backtrack;
+
+typedef struct ref_iterator_backtrack {
+ backtrack_common common;
+ /* Next iteration. */
+ struct sljit_label *matchingpath;
+} ref_iterator_backtrack;
+
+typedef struct recurse_entry {
+ struct recurse_entry *next;
+ /* Contains the function entry label. */
+ struct sljit_label *entry_label;
+ /* Contains the function entry label. */
+ struct sljit_label *backtrack_label;
+ /* Collects the entry calls until the function is not created. */
+ jump_list *entry_calls;
+ /* Collects the backtrack calls until the function is not created. */
+ jump_list *backtrack_calls;
+ /* Points to the starting opcode. */
+ sljit_sw start;
+} recurse_entry;
+
+typedef struct recurse_backtrack {
+ backtrack_common common;
+ /* Return to the matching path. */
+ struct sljit_label *matchingpath;
+ /* Recursive pattern. */
+ recurse_entry *entry;
+ /* Pattern is inlined. */
+ BOOL inlined_pattern;
+} recurse_backtrack;
+
+#define OP_THEN_TRAP OP_TABLE_LENGTH
+
+typedef struct then_trap_backtrack {
+ backtrack_common common;
+ /* If then_trap is not NULL, this structure contains the real
+ then_trap for the backtracking path. */
+ struct then_trap_backtrack *then_trap;
+ /* Points to the starting opcode. */
+ sljit_sw start;
+ /* Exit point for the then opcodes of this alternative. */
+ jump_list *quit;
+ /* Frame size of the current alternative. */
+ int framesize;
+} then_trap_backtrack;
+
+#define MAX_N_CHARS 12
+#define MAX_DIFF_CHARS 5
+
+typedef struct fast_forward_char_data {
+ /* Number of characters in the chars array, 255 for any character. */
+ sljit_u8 count;
+ /* Number of last UTF-8 characters in the chars array. */
+ sljit_u8 last_count;
+ /* Available characters in the current position. */
+ PCRE2_UCHAR chars[MAX_DIFF_CHARS];
+} fast_forward_char_data;
+
+#define MAX_CLASS_RANGE_SIZE 4
+#define MAX_CLASS_CHARS_SIZE 3
+
+typedef struct compiler_common {
+ /* The sljit ceneric compiler. */
+ struct sljit_compiler *compiler;
+ /* Compiled regular expression. */
+ pcre2_real_code *re;
+ /* First byte code. */
+ PCRE2_SPTR start;
+ /* Maps private data offset to each opcode. */
+ sljit_s32 *private_data_ptrs;
+ /* Chain list of read-only data ptrs. */
+ void *read_only_data_head;
+ /* Tells whether the capturing bracket is optimized. */
+ sljit_u8 *optimized_cbracket;
+ /* Tells whether the starting offset is a target of then. */
+ sljit_u8 *then_offsets;
+ /* Current position where a THEN must jump. */
+ then_trap_backtrack *then_trap;
+ /* Starting offset of private data for capturing brackets. */
+ sljit_s32 cbra_ptr;
+ /* Output vector starting point. Must be divisible by 2. */
+ sljit_s32 ovector_start;
+ /* Points to the starting character of the current match. */
+ sljit_s32 start_ptr;
+ /* Last known position of the requested byte. */
+ sljit_s32 req_char_ptr;
+ /* Head of the last recursion. */
+ sljit_s32 recursive_head_ptr;
+ /* First inspected character for partial matching.
+ (Needed for avoiding zero length partial matches.) */
+ sljit_s32 start_used_ptr;
+ /* Starting pointer for partial soft matches. */
+ sljit_s32 hit_start;
+ /* Pointer of the match end position. */
+ sljit_s32 match_end_ptr;
+ /* Points to the marked string. */
+ sljit_s32 mark_ptr;
+ /* Recursive control verb management chain. */
+ sljit_s32 control_head_ptr;
+ /* Points to the last matched capture block index. */
+ sljit_s32 capture_last_ptr;
+ /* Fast forward skipping byte code pointer. */
+ PCRE2_SPTR fast_forward_bc_ptr;
+ /* Locals used by fast fail optimization. */
+ sljit_s32 fast_fail_start_ptr;
+ sljit_s32 fast_fail_end_ptr;
+
+ /* Flipped and lower case tables. */
+ const sljit_u8 *fcc;
+ sljit_sw lcc;
+ /* Mode can be PCRE2_JIT_COMPLETE and others. */
+ int mode;
+ /* TRUE, when minlength is greater than 0. */
+ BOOL might_be_empty;
+ /* \K is found in the pattern. */
+ BOOL has_set_som;
+ /* (*SKIP:arg) is found in the pattern. */
+ BOOL has_skip_arg;
+ /* (*THEN) is found in the pattern. */
+ BOOL has_then;
+ /* (*SKIP) or (*SKIP:arg) is found in lookbehind assertion. */
+ BOOL has_skip_in_assert_back;
+ /* Quit is redirected by recurse, negative assertion, or positive assertion in conditional block. */
+ BOOL local_quit_available;
+ /* Currently in a positive assertion. */
+ BOOL in_positive_assertion;
+ /* Newline control. */
+ int nltype;
+ sljit_u32 nlmax;
+ sljit_u32 nlmin;
+ int newline;
+ int bsr_nltype;
+ sljit_u32 bsr_nlmax;
+ sljit_u32 bsr_nlmin;
+ /* Dollar endonly. */
+ int endonly;
+ /* Tables. */
+ sljit_sw ctypes;
+ /* Named capturing brackets. */
+ PCRE2_SPTR name_table;
+ sljit_sw name_count;
+ sljit_sw name_entry_size;
+
+ /* Labels and jump lists. */
+ struct sljit_label *partialmatchlabel;
+ struct sljit_label *quit_label;
+ struct sljit_label *abort_label;
+ struct sljit_label *accept_label;
+ struct sljit_label *ff_newline_shortcut;
+ stub_list *stubs;
+ label_addr_list *label_addrs;
+ recurse_entry *entries;
+ recurse_entry *currententry;
+ jump_list *partialmatch;
+ jump_list *quit;
+ jump_list *positive_assertion_quit;
+ jump_list *abort;
+ jump_list *failed_match;
+ jump_list *accept;
+ jump_list *calllimit;
+ jump_list *stackalloc;
+ jump_list *revertframes;
+ jump_list *wordboundary;
+ jump_list *anynewline;
+ jump_list *hspace;
+ jump_list *vspace;
+ jump_list *casefulcmp;
+ jump_list *caselesscmp;
+ jump_list *reset_match;
+ BOOL unset_backref;
+ BOOL alt_circumflex;
+#ifdef SUPPORT_UNICODE
+ BOOL utf;
+ BOOL use_ucp;
+ jump_list *getucd;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ jump_list *utfreadchar;
+ jump_list *utfreadchar16;
+ jump_list *utfreadtype8;
+#endif
+#endif /* SUPPORT_UNICODE */
+} compiler_common;
+
+/* For byte_sequence_compare. */
+
+typedef struct compare_context {
+ int length;
+ int sourcereg;
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+ int ucharptr;
+ union {
+ sljit_s32 asint;
+ sljit_u16 asushort;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ sljit_u8 asbyte;
+ sljit_u8 asuchars[4];
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ sljit_u16 asuchars[2];
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ sljit_u32 asuchars[1];
+#endif
+ } c;
+ union {
+ sljit_s32 asint;
+ sljit_u16 asushort;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ sljit_u8 asbyte;
+ sljit_u8 asuchars[4];
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ sljit_u16 asuchars[2];
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ sljit_u32 asuchars[1];
+#endif
+ } oc;
+#endif
+} compare_context;
+
+/* Undefine sljit macros. */
+#undef CMP
+
+/* Used for accessing the elements of the stack. */
+#define STACK(i) ((i) * (int)sizeof(sljit_sw))
+
+#ifdef SLJIT_PREF_SHIFT_REG
+#if SLJIT_PREF_SHIFT_REG == SLJIT_R2
+/* Nothing. */
+#elif SLJIT_PREF_SHIFT_REG == SLJIT_R3
+#define SHIFT_REG_IS_R3
+#else
+#error "Unsupported shift register"
+#endif
+#endif
+
+#define TMP1 SLJIT_R0
+#ifdef SHIFT_REG_IS_R3
+#define TMP2 SLJIT_R3
+#define TMP3 SLJIT_R2
+#else
+#define TMP2 SLJIT_R2
+#define TMP3 SLJIT_R3
+#endif
+#define STR_PTR SLJIT_R1
+#define STR_END SLJIT_S0
+#define STACK_TOP SLJIT_S1
+#define STACK_LIMIT SLJIT_S2
+#define COUNT_MATCH SLJIT_S3
+#define ARGUMENTS SLJIT_S4
+#define RETURN_ADDR SLJIT_R4
+
+/* Local space layout. */
+/* These two locals can be used by the current opcode. */
+#define LOCALS0 (0 * sizeof(sljit_sw))
+#define LOCALS1 (1 * sizeof(sljit_sw))
+/* Two local variables for possessive quantifiers (char1 cannot use them). */
+#define POSSESSIVE0 (2 * sizeof(sljit_sw))
+#define POSSESSIVE1 (3 * sizeof(sljit_sw))
+/* Max limit of recursions. */
+#define LIMIT_MATCH (4 * sizeof(sljit_sw))
+/* The output vector is stored on the stack, and contains pointers
+to characters. The vector data is divided into two groups: the first
+group contains the start / end character pointers, and the second is
+the start pointers when the end of the capturing group has not yet reached. */
+#define OVECTOR_START (common->ovector_start)
+#define OVECTOR(i) (OVECTOR_START + (i) * (sljit_sw)sizeof(sljit_sw))
+#define OVECTOR_PRIV(i) (common->cbra_ptr + (i) * (sljit_sw)sizeof(sljit_sw))
+#define PRIVATE_DATA(cc) (common->private_data_ptrs[(cc) - common->start])
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define MOV_UCHAR SLJIT_MOV_U8
+#define IN_UCHARS(x) (x)
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define MOV_UCHAR SLJIT_MOV_U16
+#define UCHAR_SHIFT (1)
+#define IN_UCHARS(x) ((x) * 2)
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#define MOV_UCHAR SLJIT_MOV_U32
+#define UCHAR_SHIFT (2)
+#define IN_UCHARS(x) ((x) * 4)
+#else
+#error Unsupported compiling mode
+#endif
+
+/* Shortcuts. */
+#define DEFINE_COMPILER \
+ struct sljit_compiler *compiler = common->compiler
+#define OP1(op, dst, dstw, src, srcw) \
+ sljit_emit_op1(compiler, (op), (dst), (dstw), (src), (srcw))
+#define OP2(op, dst, dstw, src1, src1w, src2, src2w) \
+ sljit_emit_op2(compiler, (op), (dst), (dstw), (src1), (src1w), (src2), (src2w))
+#define LABEL() \
+ sljit_emit_label(compiler)
+#define JUMP(type) \
+ sljit_emit_jump(compiler, (type))
+#define JUMPTO(type, label) \
+ sljit_set_label(sljit_emit_jump(compiler, (type)), (label))
+#define JUMPHERE(jump) \
+ sljit_set_label((jump), sljit_emit_label(compiler))
+#define SET_LABEL(jump, label) \
+ sljit_set_label((jump), (label))
+#define CMP(type, src1, src1w, src2, src2w) \
+ sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w))
+#define CMPTO(type, src1, src1w, src2, src2w, label) \
+ sljit_set_label(sljit_emit_cmp(compiler, (type), (src1), (src1w), (src2), (src2w)), (label))
+#define OP_FLAGS(op, dst, dstw, type) \
+ sljit_emit_op_flags(compiler, (op), (dst), (dstw), (type))
+#define CMOV(type, dst_reg, src, srcw) \
+ sljit_emit_cmov(compiler, (type), (dst_reg), (src), (srcw))
+#define GET_LOCAL_BASE(dst, dstw, offset) \
+ sljit_get_local_base(compiler, (dst), (dstw), (offset))
+
+#define READ_CHAR_MAX 0x7fffffff
+
+#define INVALID_UTF_CHAR 888
+
+static PCRE2_SPTR bracketend(PCRE2_SPTR cc)
+{
+SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
+do cc += GET(cc, 1); while (*cc == OP_ALT);
+SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS);
+cc += 1 + LINK_SIZE;
+return cc;
+}
+
+static int no_alternatives(PCRE2_SPTR cc)
+{
+int count = 0;
+SLJIT_ASSERT((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND));
+do
+ {
+ cc += GET(cc, 1);
+ count++;
+ }
+while (*cc == OP_ALT);
+SLJIT_ASSERT(*cc >= OP_KET && *cc <= OP_KETRPOS);
+return count;
+}
+
+/* Functions whose might need modification for all new supported opcodes:
+ next_opcode
+ check_opcode_types
+ set_private_data_ptrs
+ get_framesize
+ init_frame
+ get_recurse_data_length
+ copy_recurse_data
+ compile_matchingpath
+ compile_backtrackingpath
+*/
+
+static PCRE2_SPTR next_opcode(compiler_common *common, PCRE2_SPTR cc)
+{
+SLJIT_UNUSED_ARG(common);
+switch(*cc)
+ {
+ case OP_SOD:
+ case OP_SOM:
+ case OP_SET_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_NOTPROP:
+ case OP_PROP:
+ case OP_ANYNL:
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ case OP_EXTUNI:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ case OP_CRPOSQUERY:
+ case OP_CRPOSRANGE:
+ case OP_CLASS:
+ case OP_NCLASS:
+ case OP_REF:
+ case OP_REFI:
+ case OP_DNREF:
+ case OP_DNREFI:
+ case OP_RECURSE:
+ case OP_CALLOUT:
+ case OP_ALT:
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ case OP_REVERSE:
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_BRA:
+ case OP_BRAPOS:
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ case OP_COND:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_SCBRA:
+ case OP_SCBRAPOS:
+ case OP_SCOND:
+ case OP_CREF:
+ case OP_DNCREF:
+ case OP_RREF:
+ case OP_DNRREF:
+ case OP_FALSE:
+ case OP_TRUE:
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ case OP_PRUNE:
+ case OP_SKIP:
+ case OP_THEN:
+ case OP_COMMIT:
+ case OP_FAIL:
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ case OP_CLOSE:
+ case OP_SKIPZERO:
+ return cc + PRIV(OP_lengths)[*cc];
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ return cc;
+
+ /* Special cases. */
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ case OP_TYPEPOSUPTO:
+ return cc + PRIV(OP_lengths)[*cc] - 1;
+
+ case OP_ANYBYTE:
+#ifdef SUPPORT_UNICODE
+ if (common->utf) return NULL;
+#endif
+ return cc + 1;
+
+ case OP_CALLOUT_STR:
+ return cc + GET(cc, 1 + 2*LINK_SIZE);
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ return cc + GET(cc, 1);
+#endif
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ return cc + 1 + 2 + cc[1];
+
+ default:
+ /* All opcodes are supported now! */
+ SLJIT_UNREACHABLE();
+ return NULL;
+ }
+}
+
+static BOOL check_opcode_types(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend)
+{
+int count;
+PCRE2_SPTR slot;
+PCRE2_SPTR assert_back_end = cc - 1;
+
+/* Calculate important variables (like stack size) and checks whether all opcodes are supported. */
+while (cc < ccend)
+ {
+ switch(*cc)
+ {
+ case OP_SET_SOM:
+ common->has_set_som = TRUE;
+ common->might_be_empty = TRUE;
+ cc += 1;
+ break;
+
+ case OP_REF:
+ case OP_REFI:
+ common->optimized_cbracket[GET2(cc, 1)] = 0;
+ cc += 1 + IMM2_SIZE;
+ break;
+
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] = 0;
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_COND:
+ case OP_SCOND:
+ /* Only AUTO_CALLOUT can insert this opcode. We do
+ not intend to support this case. */
+ if (cc[1 + LINK_SIZE] == OP_CALLOUT || cc[1 + LINK_SIZE] == OP_CALLOUT_STR)
+ return FALSE;
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_CREF:
+ common->optimized_cbracket[GET2(cc, 1)] = 0;
+ cc += 1 + IMM2_SIZE;
+ break;
+
+ case OP_DNREF:
+ case OP_DNREFI:
+ case OP_DNCREF:
+ count = GET2(cc, 1 + IMM2_SIZE);
+ slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
+ while (count-- > 0)
+ {
+ common->optimized_cbracket[GET2(slot, 0)] = 0;
+ slot += common->name_entry_size;
+ }
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+
+ case OP_RECURSE:
+ /* Set its value only once. */
+ if (common->recursive_head_ptr == 0)
+ {
+ common->recursive_head_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_CALLOUT:
+ case OP_CALLOUT_STR:
+ if (common->capture_last_ptr == 0)
+ {
+ common->capture_last_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+ cc += (*cc == OP_CALLOUT) ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
+ case OP_ASSERTBACK:
+ slot = bracketend(cc);
+ if (slot > assert_back_end)
+ assert_back_end = slot;
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_THEN_ARG:
+ common->has_then = TRUE;
+ common->control_head_ptr = 1;
+ /* Fall through. */
+
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_MARK:
+ if (common->mark_ptr == 0)
+ {
+ common->mark_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_THEN:
+ common->has_then = TRUE;
+ common->control_head_ptr = 1;
+ cc += 1;
+ break;
+
+ case OP_SKIP:
+ if (cc < assert_back_end)
+ common->has_skip_in_assert_back = TRUE;
+ cc += 1;
+ break;
+
+ case OP_SKIP_ARG:
+ common->control_head_ptr = 1;
+ common->has_skip_arg = TRUE;
+ if (cc < assert_back_end)
+ common->has_skip_in_assert_back = TRUE;
+ cc += 1 + 2 + cc[1];
+ break;
+
+ default:
+ cc = next_opcode(common, cc);
+ if (cc == NULL)
+ return FALSE;
+ break;
+ }
+ }
+return TRUE;
+}
+
+static BOOL is_accelerated_repeat(PCRE2_SPTR cc)
+{
+switch(*cc)
+ {
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ return (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI);
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ return TRUE;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ cc += (*cc == OP_XCLASS) ? GET(cc, 1) : (int)(1 + (32 / sizeof(PCRE2_UCHAR)));
+#else
+ cc += (1 + (32 / sizeof(PCRE2_UCHAR)));
+#endif
+
+ switch(*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ return TRUE;
+ }
+ break;
+ }
+return FALSE;
+}
+
+static SLJIT_INLINE BOOL detect_fast_forward_skip(compiler_common *common, int *private_data_start)
+{
+PCRE2_SPTR cc = common->start;
+PCRE2_SPTR end;
+
+/* Skip not repeated brackets. */
+while (TRUE)
+ {
+ switch(*cc)
+ {
+ case OP_SOD:
+ case OP_SOM:
+ case OP_SET_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ /* Zero width assertions. */
+ cc++;
+ continue;
+ }
+
+ if (*cc != OP_BRA && *cc != OP_CBRA)
+ break;
+
+ end = cc + GET(cc, 1);
+ if (*end != OP_KET || PRIVATE_DATA(end) != 0)
+ return FALSE;
+ if (*cc == OP_CBRA)
+ {
+ if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+ return FALSE;
+ cc += IMM2_SIZE;
+ }
+ cc += 1 + LINK_SIZE;
+ }
+
+if (is_accelerated_repeat(cc))
+ {
+ common->fast_forward_bc_ptr = cc;
+ common->private_data_ptrs[(cc + 1) - common->start] = *private_data_start;
+ *private_data_start += sizeof(sljit_sw);
+ return TRUE;
+ }
+return FALSE;
+}
+
+static SLJIT_INLINE void detect_fast_fail(compiler_common *common, PCRE2_SPTR cc, int *private_data_start, sljit_s32 depth)
+{
+ PCRE2_SPTR next_alt;
+
+ SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA);
+
+ if (*cc == OP_CBRA && common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+ return;
+
+ next_alt = bracketend(cc) - (1 + LINK_SIZE);
+ if (*next_alt != OP_KET || PRIVATE_DATA(next_alt) != 0)
+ return;
+
+ do
+ {
+ next_alt = cc + GET(cc, 1);
+
+ cc += 1 + LINK_SIZE + ((*cc == OP_CBRA) ? IMM2_SIZE : 0);
+
+ while (TRUE)
+ {
+ switch(*cc)
+ {
+ case OP_SOD:
+ case OP_SOM:
+ case OP_SET_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ /* Zero width assertions. */
+ cc++;
+ continue;
+ }
+ break;
+ }
+
+ if (depth > 0 && (*cc == OP_BRA || *cc == OP_CBRA))
+ detect_fast_fail(common, cc, private_data_start, depth - 1);
+
+ if (is_accelerated_repeat(cc))
+ {
+ common->private_data_ptrs[(cc + 1) - common->start] = *private_data_start;
+
+ if (common->fast_fail_start_ptr == 0)
+ common->fast_fail_start_ptr = *private_data_start;
+
+ *private_data_start += sizeof(sljit_sw);
+ common->fast_fail_end_ptr = *private_data_start;
+
+ if (*private_data_start > SLJIT_MAX_LOCAL_SIZE)
+ return;
+ }
+
+ cc = next_alt;
+ }
+ while (*cc == OP_ALT);
+}
+
+static int get_class_iterator_size(PCRE2_SPTR cc)
+{
+sljit_u32 min;
+sljit_u32 max;
+switch(*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRPLUS:
+ return 2;
+
+ case OP_CRMINSTAR:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ return 1;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ min = GET2(cc, 1);
+ max = GET2(cc, 1 + IMM2_SIZE);
+ if (max == 0)
+ return (*cc == OP_CRRANGE) ? 2 : 1;
+ max -= min;
+ if (max > 2)
+ max = 2;
+ return max;
+
+ default:
+ return 0;
+ }
+}
+
+static BOOL detect_repeat(compiler_common *common, PCRE2_SPTR begin)
+{
+PCRE2_SPTR end = bracketend(begin);
+PCRE2_SPTR next;
+PCRE2_SPTR next_end;
+PCRE2_SPTR max_end;
+PCRE2_UCHAR type;
+sljit_sw length = end - begin;
+sljit_s32 min, max, i;
+
+/* Detect fixed iterations first. */
+if (end[-(1 + LINK_SIZE)] != OP_KET)
+ return FALSE;
+
+/* Already detected repeat. */
+if (common->private_data_ptrs[end - common->start - LINK_SIZE] != 0)
+ return TRUE;
+
+next = end;
+min = 1;
+while (1)
+ {
+ if (*next != *begin)
+ break;
+ next_end = bracketend(next);
+ if (next_end - next != length || memcmp(begin, next, IN_UCHARS(length)) != 0)
+ break;
+ next = next_end;
+ min++;
+ }
+
+if (min == 2)
+ return FALSE;
+
+max = 0;
+max_end = next;
+if (*next == OP_BRAZERO || *next == OP_BRAMINZERO)
+ {
+ type = *next;
+ while (1)
+ {
+ if (next[0] != type || next[1] != OP_BRA || next[2 + LINK_SIZE] != *begin)
+ break;
+ next_end = bracketend(next + 2 + LINK_SIZE);
+ if (next_end - next != (length + 2 + LINK_SIZE) || memcmp(begin, next + 2 + LINK_SIZE, IN_UCHARS(length)) != 0)
+ break;
+ next = next_end;
+ max++;
+ }
+
+ if (next[0] == type && next[1] == *begin && max >= 1)
+ {
+ next_end = bracketend(next + 1);
+ if (next_end - next == (length + 1) && memcmp(begin, next + 1, IN_UCHARS(length)) == 0)
+ {
+ for (i = 0; i < max; i++, next_end += 1 + LINK_SIZE)
+ if (*next_end != OP_KET)
+ break;
+
+ if (i == max)
+ {
+ common->private_data_ptrs[max_end - common->start - LINK_SIZE] = next_end - max_end;
+ common->private_data_ptrs[max_end - common->start - LINK_SIZE + 1] = (type == OP_BRAZERO) ? OP_UPTO : OP_MINUPTO;
+ /* +2 the original and the last. */
+ common->private_data_ptrs[max_end - common->start - LINK_SIZE + 2] = max + 2;
+ if (min == 1)
+ return TRUE;
+ min--;
+ max_end -= (1 + LINK_SIZE) + GET(max_end, -LINK_SIZE);
+ }
+ }
+ }
+ }
+
+if (min >= 3)
+ {
+ common->private_data_ptrs[end - common->start - LINK_SIZE] = max_end - end;
+ common->private_data_ptrs[end - common->start - LINK_SIZE + 1] = OP_EXACT;
+ common->private_data_ptrs[end - common->start - LINK_SIZE + 2] = min;
+ return TRUE;
+ }
+
+return FALSE;
+}
+
+#define CASE_ITERATOR_PRIVATE_DATA_1 \
+ case OP_MINSTAR: \
+ case OP_MINPLUS: \
+ case OP_QUERY: \
+ case OP_MINQUERY: \
+ case OP_MINSTARI: \
+ case OP_MINPLUSI: \
+ case OP_QUERYI: \
+ case OP_MINQUERYI: \
+ case OP_NOTMINSTAR: \
+ case OP_NOTMINPLUS: \
+ case OP_NOTQUERY: \
+ case OP_NOTMINQUERY: \
+ case OP_NOTMINSTARI: \
+ case OP_NOTMINPLUSI: \
+ case OP_NOTQUERYI: \
+ case OP_NOTMINQUERYI:
+
+#define CASE_ITERATOR_PRIVATE_DATA_2A \
+ case OP_STAR: \
+ case OP_PLUS: \
+ case OP_STARI: \
+ case OP_PLUSI: \
+ case OP_NOTSTAR: \
+ case OP_NOTPLUS: \
+ case OP_NOTSTARI: \
+ case OP_NOTPLUSI:
+
+#define CASE_ITERATOR_PRIVATE_DATA_2B \
+ case OP_UPTO: \
+ case OP_MINUPTO: \
+ case OP_UPTOI: \
+ case OP_MINUPTOI: \
+ case OP_NOTUPTO: \
+ case OP_NOTMINUPTO: \
+ case OP_NOTUPTOI: \
+ case OP_NOTMINUPTOI:
+
+#define CASE_ITERATOR_TYPE_PRIVATE_DATA_1 \
+ case OP_TYPEMINSTAR: \
+ case OP_TYPEMINPLUS: \
+ case OP_TYPEQUERY: \
+ case OP_TYPEMINQUERY:
+
+#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2A \
+ case OP_TYPESTAR: \
+ case OP_TYPEPLUS:
+
+#define CASE_ITERATOR_TYPE_PRIVATE_DATA_2B \
+ case OP_TYPEUPTO: \
+ case OP_TYPEMINUPTO:
+
+static void set_private_data_ptrs(compiler_common *common, int *private_data_start, PCRE2_SPTR ccend)
+{
+PCRE2_SPTR cc = common->start;
+PCRE2_SPTR alternative;
+PCRE2_SPTR end = NULL;
+int private_data_ptr = *private_data_start;
+int space, size, bracketlen;
+BOOL repeat_check = TRUE;
+
+while (cc < ccend)
+ {
+ space = 0;
+ size = 0;
+ bracketlen = 0;
+ if (private_data_ptr > SLJIT_MAX_LOCAL_SIZE)
+ break;
+
+ if (repeat_check && (*cc == OP_ONCE || *cc == OP_BRA || *cc == OP_CBRA || *cc == OP_COND))
+ {
+ if (detect_repeat(common, cc))
+ {
+ /* These brackets are converted to repeats, so no global
+ based single character repeat is allowed. */
+ if (cc >= end)
+ end = bracketend(cc);
+ }
+ }
+ repeat_check = TRUE;
+
+ switch(*cc)
+ {
+ case OP_KET:
+ if (common->private_data_ptrs[cc + 1 - common->start] != 0)
+ {
+ common->private_data_ptrs[cc - common->start] = private_data_ptr;
+ private_data_ptr += sizeof(sljit_sw);
+ cc += common->private_data_ptrs[cc + 1 - common->start];
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_BRAPOS:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_SCOND:
+ common->private_data_ptrs[cc - common->start] = private_data_ptr;
+ private_data_ptr += sizeof(sljit_sw);
+ bracketlen = 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ common->private_data_ptrs[cc - common->start] = private_data_ptr;
+ private_data_ptr += sizeof(sljit_sw);
+ bracketlen = 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_COND:
+ /* Might be a hidden SCOND. */
+ alternative = cc + GET(cc, 1);
+ if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+ {
+ common->private_data_ptrs[cc - common->start] = private_data_ptr;
+ private_data_ptr += sizeof(sljit_sw);
+ }
+ bracketlen = 1 + LINK_SIZE;
+ break;
+
+ case OP_BRA:
+ bracketlen = 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ bracketlen = 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ repeat_check = FALSE;
+ size = 1;
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_1
+ space = 1;
+ size = -2;
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_2A
+ space = 2;
+ size = -2;
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_2B
+ space = 2;
+ size = -(2 + IMM2_SIZE);
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+ space = 1;
+ size = 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+ if (cc[1] != OP_ANYNL && cc[1] != OP_EXTUNI)
+ space = 2;
+ size = 1;
+ break;
+
+ case OP_TYPEUPTO:
+ if (cc[1 + IMM2_SIZE] != OP_ANYNL && cc[1 + IMM2_SIZE] != OP_EXTUNI)
+ space = 2;
+ size = 1 + IMM2_SIZE;
+ break;
+
+ case OP_TYPEMINUPTO:
+ space = 2;
+ size = 1 + IMM2_SIZE;
+ break;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ space = get_class_iterator_size(cc + size);
+ size = 1 + 32 / sizeof(PCRE2_UCHAR);
+ break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ space = get_class_iterator_size(cc + size);
+ size = GET(cc, 1);
+ break;
+#endif
+
+ default:
+ cc = next_opcode(common, cc);
+ SLJIT_ASSERT(cc != NULL);
+ break;
+ }
+
+ /* Character iterators, which are not inside a repeated bracket,
+ gets a private slot instead of allocating it on the stack. */
+ if (space > 0 && cc >= end)
+ {
+ common->private_data_ptrs[cc - common->start] = private_data_ptr;
+ private_data_ptr += sizeof(sljit_sw) * space;
+ }
+
+ if (size != 0)
+ {
+ if (size < 0)
+ {
+ cc += -size;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ }
+ else
+ cc += size;
+ }
+
+ if (bracketlen > 0)
+ {
+ if (cc >= end)
+ {
+ end = bracketend(cc);
+ if (end[-1 - LINK_SIZE] == OP_KET)
+ end = NULL;
+ }
+ cc += bracketlen;
+ }
+ }
+*private_data_start = private_data_ptr;
+}
+
+/* Returns with a frame_types (always < 0) if no need for frame. */
+static int get_framesize(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, BOOL recursive, BOOL *needs_control_head)
+{
+int length = 0;
+int possessive = 0;
+BOOL stack_restore = FALSE;
+BOOL setsom_found = recursive;
+BOOL setmark_found = recursive;
+/* The last capture is a local variable even for recursions. */
+BOOL capture_last_found = FALSE;
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+SLJIT_ASSERT(common->control_head_ptr != 0);
+*needs_control_head = TRUE;
+#else
+*needs_control_head = FALSE;
+#endif
+
+if (ccend == NULL)
+ {
+ ccend = bracketend(cc) - (1 + LINK_SIZE);
+ if (!recursive && (*cc == OP_CBRAPOS || *cc == OP_SCBRAPOS))
+ {
+ possessive = length = (common->capture_last_ptr != 0) ? 5 : 3;
+ /* This is correct regardless of common->capture_last_ptr. */
+ capture_last_found = TRUE;
+ }
+ cc = next_opcode(common, cc);
+ }
+
+SLJIT_ASSERT(cc != NULL);
+while (cc < ccend)
+ switch(*cc)
+ {
+ case OP_SET_SOM:
+ SLJIT_ASSERT(common->has_set_som);
+ stack_restore = TRUE;
+ if (!setsom_found)
+ {
+ length += 2;
+ setsom_found = TRUE;
+ }
+ cc += 1;
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_THEN_ARG:
+ SLJIT_ASSERT(common->mark_ptr != 0);
+ stack_restore = TRUE;
+ if (!setmark_found)
+ {
+ length += 2;
+ setmark_found = TRUE;
+ }
+ if (common->control_head_ptr != 0)
+ *needs_control_head = TRUE;
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_RECURSE:
+ stack_restore = TRUE;
+ if (common->has_set_som && !setsom_found)
+ {
+ length += 2;
+ setsom_found = TRUE;
+ }
+ if (common->mark_ptr != 0 && !setmark_found)
+ {
+ length += 2;
+ setmark_found = TRUE;
+ }
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ length += 2;
+ capture_last_found = TRUE;
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRA:
+ case OP_SCBRAPOS:
+ stack_restore = TRUE;
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ length += 2;
+ capture_last_found = TRUE;
+ }
+ length += 3;
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_THEN:
+ stack_restore = TRUE;
+ if (common->control_head_ptr != 0)
+ *needs_control_head = TRUE;
+ cc ++;
+ break;
+
+ default:
+ stack_restore = TRUE;
+ /* Fall through. */
+
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_ANYBYTE:
+ case OP_NOTPROP:
+ case OP_PROP:
+ case OP_ANYNL:
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ case OP_EXTUNI:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ case OP_TYPEPOSUPTO:
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ case OP_XCLASS:
+
+ case OP_CALLOUT:
+ case OP_CALLOUT_STR:
+
+ cc = next_opcode(common, cc);
+ SLJIT_ASSERT(cc != NULL);
+ break;
+ }
+
+/* Possessive quantifiers can use a special case. */
+if (SLJIT_UNLIKELY(possessive == length))
+ return stack_restore ? no_frame : no_stack;
+
+if (length > 0)
+ return length + 1;
+return stack_restore ? no_frame : no_stack;
+}
+
+static void init_frame(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, int stackpos, int stacktop)
+{
+DEFINE_COMPILER;
+BOOL setsom_found = FALSE;
+BOOL setmark_found = FALSE;
+/* The last capture is a local variable even for recursions. */
+BOOL capture_last_found = FALSE;
+int offset;
+
+/* >= 1 + shortest item size (2) */
+SLJIT_UNUSED_ARG(stacktop);
+SLJIT_ASSERT(stackpos >= stacktop + 2);
+
+stackpos = STACK(stackpos);
+if (ccend == NULL)
+ {
+ ccend = bracketend(cc) - (1 + LINK_SIZE);
+ if (*cc != OP_CBRAPOS && *cc != OP_SCBRAPOS)
+ cc = next_opcode(common, cc);
+ }
+
+SLJIT_ASSERT(cc != NULL);
+while (cc < ccend)
+ switch(*cc)
+ {
+ case OP_SET_SOM:
+ SLJIT_ASSERT(common->has_set_som);
+ if (!setsom_found)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0));
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ setsom_found = TRUE;
+ }
+ cc += 1;
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_THEN_ARG:
+ SLJIT_ASSERT(common->mark_ptr != 0);
+ if (!setmark_found)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr);
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ setmark_found = TRUE;
+ }
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_RECURSE:
+ if (common->has_set_som && !setsom_found)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -OVECTOR(0));
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ setsom_found = TRUE;
+ }
+ if (common->mark_ptr != 0 && !setmark_found)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->mark_ptr);
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ setmark_found = TRUE;
+ }
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr);
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ capture_last_found = TRUE;
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRA:
+ case OP_SCBRAPOS:
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, -common->capture_last_ptr);
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ capture_last_found = TRUE;
+ }
+ offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, OVECTOR(offset));
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP1, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, TMP2, 0);
+ stackpos -= (int)sizeof(sljit_sw);
+
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ default:
+ cc = next_opcode(common, cc);
+ SLJIT_ASSERT(cc != NULL);
+ break;
+ }
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), stackpos, SLJIT_IMM, 0);
+SLJIT_ASSERT(stackpos == STACK(stacktop));
+}
+
+#define RECURSE_TMP_REG_COUNT 3
+
+typedef struct delayed_mem_copy_status {
+ struct sljit_compiler *compiler;
+ int store_bases[RECURSE_TMP_REG_COUNT];
+ int store_offsets[RECURSE_TMP_REG_COUNT];
+ int tmp_regs[RECURSE_TMP_REG_COUNT];
+ int saved_tmp_regs[RECURSE_TMP_REG_COUNT];
+ int next_tmp_reg;
+} delayed_mem_copy_status;
+
+static void delayed_mem_copy_init(delayed_mem_copy_status *status, compiler_common *common)
+{
+int i;
+
+for (i = 0; i < RECURSE_TMP_REG_COUNT; i++)
+ {
+ SLJIT_ASSERT(status->tmp_regs[i] >= 0);
+ SLJIT_ASSERT(sljit_get_register_index(status->saved_tmp_regs[i]) < 0 || status->tmp_regs[i] == status->saved_tmp_regs[i]);
+
+ status->store_bases[i] = -1;
+ }
+status->next_tmp_reg = 0;
+status->compiler = common->compiler;
+}
+
+static void delayed_mem_copy_move(delayed_mem_copy_status *status, int load_base, sljit_sw load_offset,
+ int store_base, sljit_sw store_offset)
+{
+struct sljit_compiler *compiler = status->compiler;
+int next_tmp_reg = status->next_tmp_reg;
+int tmp_reg = status->tmp_regs[next_tmp_reg];
+
+SLJIT_ASSERT(load_base > 0 && store_base > 0);
+
+if (status->store_bases[next_tmp_reg] == -1)
+ {
+ /* Preserve virtual registers. */
+ if (sljit_get_register_index(status->saved_tmp_regs[next_tmp_reg]) < 0)
+ OP1(SLJIT_MOV, status->saved_tmp_regs[next_tmp_reg], 0, tmp_reg, 0);
+ }
+else
+ OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0);
+
+OP1(SLJIT_MOV, tmp_reg, 0, SLJIT_MEM1(load_base), load_offset);
+status->store_bases[next_tmp_reg] = store_base;
+status->store_offsets[next_tmp_reg] = store_offset;
+
+status->next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT;
+}
+
+static void delayed_mem_copy_finish(delayed_mem_copy_status *status)
+{
+struct sljit_compiler *compiler = status->compiler;
+int next_tmp_reg = status->next_tmp_reg;
+int tmp_reg, saved_tmp_reg, i;
+
+for (i = 0; i < RECURSE_TMP_REG_COUNT; i++)
+ {
+ if (status->store_bases[next_tmp_reg] != -1)
+ {
+ tmp_reg = status->tmp_regs[next_tmp_reg];
+ saved_tmp_reg = status->saved_tmp_regs[next_tmp_reg];
+
+ OP1(SLJIT_MOV, SLJIT_MEM1(status->store_bases[next_tmp_reg]), status->store_offsets[next_tmp_reg], tmp_reg, 0);
+
+ /* Restore virtual registers. */
+ if (sljit_get_register_index(saved_tmp_reg) < 0)
+ OP1(SLJIT_MOV, tmp_reg, 0, saved_tmp_reg, 0);
+ }
+
+ next_tmp_reg = (next_tmp_reg + 1) % RECURSE_TMP_REG_COUNT;
+ }
+}
+
+#undef RECURSE_TMP_REG_COUNT
+
+static int get_recurse_data_length(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend,
+ BOOL *needs_control_head, BOOL *has_quit, BOOL *has_accept)
+{
+int length = 1;
+int size;
+PCRE2_SPTR alternative;
+BOOL quit_found = FALSE;
+BOOL accept_found = FALSE;
+BOOL setsom_found = FALSE;
+BOOL setmark_found = FALSE;
+BOOL capture_last_found = FALSE;
+BOOL control_head_found = FALSE;
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+SLJIT_ASSERT(common->control_head_ptr != 0);
+control_head_found = TRUE;
+#endif
+
+/* Calculate the sum of the private machine words. */
+while (cc < ccend)
+ {
+ size = 0;
+ switch(*cc)
+ {
+ case OP_SET_SOM:
+ SLJIT_ASSERT(common->has_set_som);
+ setsom_found = TRUE;
+ cc += 1;
+ break;
+
+ case OP_RECURSE:
+ if (common->has_set_som)
+ setsom_found = TRUE;
+ if (common->mark_ptr != 0)
+ setmark_found = TRUE;
+ if (common->capture_last_ptr != 0)
+ capture_last_found = TRUE;
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_KET:
+ if (PRIVATE_DATA(cc) != 0)
+ {
+ length++;
+ SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0);
+ cc += PRIVATE_DATA(cc + 1);
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_BRAPOS:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_SCOND:
+ length++;
+ SLJIT_ASSERT(PRIVATE_DATA(cc) != 0);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ length += 2;
+ if (common->capture_last_ptr != 0)
+ capture_last_found = TRUE;
+ if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+ length++;
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ length += 2 + 2;
+ if (common->capture_last_ptr != 0)
+ capture_last_found = TRUE;
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_COND:
+ /* Might be a hidden SCOND. */
+ alternative = cc + GET(cc, 1);
+ if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+ length++;
+ cc += 1 + LINK_SIZE;
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_1
+ if (PRIVATE_DATA(cc) != 0)
+ length++;
+ cc += 2;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_2A
+ if (PRIVATE_DATA(cc) != 0)
+ length += 2;
+ cc += 2;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_2B
+ if (PRIVATE_DATA(cc) != 0)
+ length += 2;
+ cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+ if (PRIVATE_DATA(cc) != 0)
+ length++;
+ cc += 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+ if (PRIVATE_DATA(cc) != 0)
+ length += 2;
+ cc += 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+ if (PRIVATE_DATA(cc) != 0)
+ length += 2;
+ cc += 1 + IMM2_SIZE;
+ break;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ size = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#else
+ size = 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#endif
+ if (PRIVATE_DATA(cc) != 0)
+ length += get_class_iterator_size(cc + size);
+ cc += size;
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_THEN_ARG:
+ SLJIT_ASSERT(common->mark_ptr != 0);
+ if (!setmark_found)
+ setmark_found = TRUE;
+ if (common->control_head_ptr != 0)
+ control_head_found = TRUE;
+ if (*cc != OP_MARK)
+ quit_found = TRUE;
+
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_PRUNE:
+ case OP_SKIP:
+ case OP_COMMIT:
+ quit_found = TRUE;
+ cc++;
+ break;
+
+ case OP_SKIP_ARG:
+ quit_found = TRUE;
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_THEN:
+ SLJIT_ASSERT(common->control_head_ptr != 0);
+ quit_found = TRUE;
+ if (!control_head_found)
+ control_head_found = TRUE;
+ cc++;
+ break;
+
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ accept_found = TRUE;
+ cc++;
+ break;
+
+ default:
+ cc = next_opcode(common, cc);
+ SLJIT_ASSERT(cc != NULL);
+ break;
+ }
+ }
+SLJIT_ASSERT(cc == ccend);
+
+if (control_head_found)
+ length++;
+if (capture_last_found)
+ length++;
+if (quit_found)
+ {
+ if (setsom_found)
+ length++;
+ if (setmark_found)
+ length++;
+ }
+
+*needs_control_head = control_head_found;
+*has_quit = quit_found;
+*has_accept = accept_found;
+return length;
+}
+
+enum copy_recurse_data_types {
+ recurse_copy_from_global,
+ recurse_copy_private_to_global,
+ recurse_copy_shared_to_global,
+ recurse_copy_kept_shared_to_global,
+ recurse_swap_global
+};
+
+static void copy_recurse_data(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend,
+ int type, int stackptr, int stacktop, BOOL has_quit)
+{
+delayed_mem_copy_status status;
+PCRE2_SPTR alternative;
+sljit_sw private_srcw[2];
+sljit_sw shared_srcw[3];
+sljit_sw kept_shared_srcw[2];
+int private_count, shared_count, kept_shared_count;
+int from_sp, base_reg, offset, i;
+BOOL setsom_found = FALSE;
+BOOL setmark_found = FALSE;
+BOOL capture_last_found = FALSE;
+BOOL control_head_found = FALSE;
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+SLJIT_ASSERT(common->control_head_ptr != 0);
+control_head_found = TRUE;
+#endif
+
+switch (type)
+ {
+ case recurse_copy_from_global:
+ from_sp = TRUE;
+ base_reg = STACK_TOP;
+ break;
+
+ case recurse_copy_private_to_global:
+ case recurse_copy_shared_to_global:
+ case recurse_copy_kept_shared_to_global:
+ from_sp = FALSE;
+ base_reg = STACK_TOP;
+ break;
+
+ default:
+ SLJIT_ASSERT(type == recurse_swap_global);
+ from_sp = FALSE;
+ base_reg = TMP2;
+ break;
+ }
+
+stackptr = STACK(stackptr);
+stacktop = STACK(stacktop);
+
+status.tmp_regs[0] = TMP1;
+status.saved_tmp_regs[0] = TMP1;
+
+if (base_reg != TMP2)
+ {
+ status.tmp_regs[1] = TMP2;
+ status.saved_tmp_regs[1] = TMP2;
+ }
+else
+ {
+ status.saved_tmp_regs[1] = RETURN_ADDR;
+ if (sljit_get_register_index (RETURN_ADDR) == -1)
+ status.tmp_regs[1] = STR_PTR;
+ else
+ status.tmp_regs[1] = RETURN_ADDR;
+ }
+
+status.saved_tmp_regs[2] = TMP3;
+if (sljit_get_register_index (TMP3) == -1)
+ status.tmp_regs[2] = STR_END;
+else
+ status.tmp_regs[2] = TMP3;
+
+delayed_mem_copy_init(&status, common);
+
+if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global)
+ {
+ SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global);
+
+ if (!from_sp)
+ delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->recursive_head_ptr);
+
+ if (from_sp || type == recurse_swap_global)
+ delayed_mem_copy_move(&status, SLJIT_SP, common->recursive_head_ptr, base_reg, stackptr);
+ }
+
+stackptr += sizeof(sljit_sw);
+
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+if (type != recurse_copy_shared_to_global)
+ {
+ if (!from_sp)
+ delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, common->control_head_ptr);
+
+ if (from_sp || type == recurse_swap_global)
+ delayed_mem_copy_move(&status, SLJIT_SP, common->control_head_ptr, base_reg, stackptr);
+ }
+
+stackptr += sizeof(sljit_sw);
+#endif
+
+while (cc < ccend)
+ {
+ private_count = 0;
+ shared_count = 0;
+ kept_shared_count = 0;
+
+ switch(*cc)
+ {
+ case OP_SET_SOM:
+ SLJIT_ASSERT(common->has_set_som);
+ if (has_quit && !setsom_found)
+ {
+ kept_shared_srcw[0] = OVECTOR(0);
+ kept_shared_count = 1;
+ setsom_found = TRUE;
+ }
+ cc += 1;
+ break;
+
+ case OP_RECURSE:
+ if (has_quit)
+ {
+ if (common->has_set_som && !setsom_found)
+ {
+ kept_shared_srcw[0] = OVECTOR(0);
+ kept_shared_count = 1;
+ setsom_found = TRUE;
+ }
+ if (common->mark_ptr != 0 && !setmark_found)
+ {
+ kept_shared_srcw[kept_shared_count] = common->mark_ptr;
+ kept_shared_count++;
+ setmark_found = TRUE;
+ }
+ }
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ shared_srcw[0] = common->capture_last_ptr;
+ shared_count = 1;
+ capture_last_found = TRUE;
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_KET:
+ if (PRIVATE_DATA(cc) != 0)
+ {
+ private_count = 1;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ SLJIT_ASSERT(PRIVATE_DATA(cc + 1) != 0);
+ cc += PRIVATE_DATA(cc + 1);
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_BRAPOS:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_SCOND:
+ private_count = 1;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
+ shared_srcw[0] = OVECTOR(offset);
+ shared_srcw[1] = OVECTOR(offset + 1);
+ shared_count = 2;
+
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ shared_srcw[2] = common->capture_last_ptr;
+ shared_count = 3;
+ capture_last_found = TRUE;
+ }
+
+ if (common->optimized_cbracket[GET2(cc, 1 + LINK_SIZE)] == 0)
+ {
+ private_count = 1;
+ private_srcw[0] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+ }
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ offset = (GET2(cc, 1 + LINK_SIZE)) << 1;
+ shared_srcw[0] = OVECTOR(offset);
+ shared_srcw[1] = OVECTOR(offset + 1);
+ shared_count = 2;
+
+ if (common->capture_last_ptr != 0 && !capture_last_found)
+ {
+ shared_srcw[2] = common->capture_last_ptr;
+ shared_count = 3;
+ capture_last_found = TRUE;
+ }
+
+ private_count = 2;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ private_srcw[1] = OVECTOR_PRIV(GET2(cc, 1 + LINK_SIZE));
+ cc += 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ case OP_COND:
+ /* Might be a hidden SCOND. */
+ alternative = cc + GET(cc, 1);
+ if (*alternative == OP_KETRMAX || *alternative == OP_KETRMIN)
+ {
+ private_count = 1;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ }
+ cc += 1 + LINK_SIZE;
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_1
+ if (PRIVATE_DATA(cc))
+ {
+ private_count = 1;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ }
+ cc += 2;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_2A
+ if (PRIVATE_DATA(cc))
+ {
+ private_count = 2;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ private_srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
+ }
+ cc += 2;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ CASE_ITERATOR_PRIVATE_DATA_2B
+ if (PRIVATE_DATA(cc))
+ {
+ private_count = 2;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ private_srcw[1] = PRIVATE_DATA(cc) + sizeof(sljit_sw);
+ }
+ cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+ if (PRIVATE_DATA(cc))
+ {
+ private_count = 1;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ }
+ cc += 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+ if (PRIVATE_DATA(cc))
+ {
+ private_count = 2;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ private_srcw[1] = private_srcw[0] + sizeof(sljit_sw);
+ }
+ cc += 1;
+ break;
+
+ CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+ if (PRIVATE_DATA(cc))
+ {
+ private_count = 2;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ private_srcw[1] = private_srcw[0] + sizeof(sljit_sw);
+ }
+ cc += 1 + IMM2_SIZE;
+ break;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ i = (*cc == OP_XCLASS) ? GET(cc, 1) : 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#else
+ i = 1 + 32 / (int)sizeof(PCRE2_UCHAR);
+#endif
+ if (PRIVATE_DATA(cc) != 0)
+ switch(get_class_iterator_size(cc + i))
+ {
+ case 1:
+ private_count = 1;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ break;
+
+ case 2:
+ private_count = 2;
+ private_srcw[0] = PRIVATE_DATA(cc);
+ private_srcw[1] = private_srcw[0] + sizeof(sljit_sw);
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ cc += i;
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_THEN_ARG:
+ SLJIT_ASSERT(common->mark_ptr != 0);
+ if (has_quit && !setmark_found)
+ {
+ kept_shared_srcw[0] = common->mark_ptr;
+ kept_shared_count = 1;
+ setmark_found = TRUE;
+ }
+ if (common->control_head_ptr != 0 && !control_head_found)
+ {
+ shared_srcw[0] = common->control_head_ptr;
+ shared_count = 1;
+ control_head_found = TRUE;
+ }
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_THEN:
+ SLJIT_ASSERT(common->control_head_ptr != 0);
+ if (!control_head_found)
+ {
+ shared_srcw[0] = common->control_head_ptr;
+ shared_count = 1;
+ control_head_found = TRUE;
+ }
+ cc++;
+ break;
+
+ default:
+ cc = next_opcode(common, cc);
+ SLJIT_ASSERT(cc != NULL);
+ break;
+ }
+
+ if (type != recurse_copy_shared_to_global && type != recurse_copy_kept_shared_to_global)
+ {
+ SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_private_to_global || type == recurse_swap_global);
+
+ for (i = 0; i < private_count; i++)
+ {
+ SLJIT_ASSERT(private_srcw[i] != 0);
+
+ if (!from_sp)
+ delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, private_srcw[i]);
+
+ if (from_sp || type == recurse_swap_global)
+ delayed_mem_copy_move(&status, SLJIT_SP, private_srcw[i], base_reg, stackptr);
+
+ stackptr += sizeof(sljit_sw);
+ }
+ }
+ else
+ stackptr += sizeof(sljit_sw) * private_count;
+
+ if (type != recurse_copy_private_to_global && type != recurse_copy_kept_shared_to_global)
+ {
+ SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_swap_global);
+
+ for (i = 0; i < shared_count; i++)
+ {
+ SLJIT_ASSERT(shared_srcw[i] != 0);
+
+ if (!from_sp)
+ delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, shared_srcw[i]);
+
+ if (from_sp || type == recurse_swap_global)
+ delayed_mem_copy_move(&status, SLJIT_SP, shared_srcw[i], base_reg, stackptr);
+
+ stackptr += sizeof(sljit_sw);
+ }
+ }
+ else
+ stackptr += sizeof(sljit_sw) * shared_count;
+
+ if (type != recurse_copy_private_to_global && type != recurse_swap_global)
+ {
+ SLJIT_ASSERT(type == recurse_copy_from_global || type == recurse_copy_shared_to_global || type == recurse_copy_kept_shared_to_global);
+
+ for (i = 0; i < kept_shared_count; i++)
+ {
+ SLJIT_ASSERT(kept_shared_srcw[i] != 0);
+
+ if (!from_sp)
+ delayed_mem_copy_move(&status, base_reg, stackptr, SLJIT_SP, kept_shared_srcw[i]);
+
+ if (from_sp || type == recurse_swap_global)
+ delayed_mem_copy_move(&status, SLJIT_SP, kept_shared_srcw[i], base_reg, stackptr);
+
+ stackptr += sizeof(sljit_sw);
+ }
+ }
+ else
+ stackptr += sizeof(sljit_sw) * kept_shared_count;
+ }
+
+SLJIT_ASSERT(cc == ccend && stackptr == stacktop);
+
+delayed_mem_copy_finish(&status);
+}
+
+static SLJIT_INLINE PCRE2_SPTR set_then_offsets(compiler_common *common, PCRE2_SPTR cc, sljit_u8 *current_offset)
+{
+PCRE2_SPTR end = bracketend(cc);
+BOOL has_alternatives = cc[GET(cc, 1)] == OP_ALT;
+
+/* Assert captures then. */
+if (*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT)
+ current_offset = NULL;
+/* Conditional block does not. */
+if (*cc == OP_COND || *cc == OP_SCOND)
+ has_alternatives = FALSE;
+
+cc = next_opcode(common, cc);
+if (has_alternatives)
+ current_offset = common->then_offsets + (cc - common->start);
+
+while (cc < end)
+ {
+ if ((*cc >= OP_ASSERT && *cc <= OP_ASSERTBACK_NOT) || (*cc >= OP_ONCE && *cc <= OP_SCOND))
+ cc = set_then_offsets(common, cc, current_offset);
+ else
+ {
+ if (*cc == OP_ALT && has_alternatives)
+ current_offset = common->then_offsets + (cc + 1 + LINK_SIZE - common->start);
+ if (*cc >= OP_THEN && *cc <= OP_THEN_ARG && current_offset != NULL)
+ *current_offset = 1;
+ cc = next_opcode(common, cc);
+ }
+ }
+
+return end;
+}
+
+#undef CASE_ITERATOR_PRIVATE_DATA_1
+#undef CASE_ITERATOR_PRIVATE_DATA_2A
+#undef CASE_ITERATOR_PRIVATE_DATA_2B
+#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_1
+#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2A
+#undef CASE_ITERATOR_TYPE_PRIVATE_DATA_2B
+
+static SLJIT_INLINE BOOL is_powerof2(unsigned int value)
+{
+return (value & (value - 1)) == 0;
+}
+
+static SLJIT_INLINE void set_jumps(jump_list *list, struct sljit_label *label)
+{
+while (list)
+ {
+ /* sljit_set_label is clever enough to do nothing
+ if either the jump or the label is NULL. */
+ SET_LABEL(list->jump, label);
+ list = list->next;
+ }
+}
+
+static SLJIT_INLINE void add_jump(struct sljit_compiler *compiler, jump_list **list, struct sljit_jump *jump)
+{
+jump_list *list_item = sljit_alloc_memory(compiler, sizeof(jump_list));
+if (list_item)
+ {
+ list_item->next = *list;
+ list_item->jump = jump;
+ *list = list_item;
+ }
+}
+
+static void add_stub(compiler_common *common, struct sljit_jump *start)
+{
+DEFINE_COMPILER;
+stub_list *list_item = sljit_alloc_memory(compiler, sizeof(stub_list));
+
+if (list_item)
+ {
+ list_item->start = start;
+ list_item->quit = LABEL();
+ list_item->next = common->stubs;
+ common->stubs = list_item;
+ }
+}
+
+static void flush_stubs(compiler_common *common)
+{
+DEFINE_COMPILER;
+stub_list *list_item = common->stubs;
+
+while (list_item)
+ {
+ JUMPHERE(list_item->start);
+ add_jump(compiler, &common->stackalloc, JUMP(SLJIT_FAST_CALL));
+ JUMPTO(SLJIT_JUMP, list_item->quit);
+ list_item = list_item->next;
+ }
+common->stubs = NULL;
+}
+
+static void add_label_addr(compiler_common *common, sljit_uw *update_addr)
+{
+DEFINE_COMPILER;
+label_addr_list *label_addr;
+
+label_addr = sljit_alloc_memory(compiler, sizeof(label_addr_list));
+if (label_addr == NULL)
+ return;
+label_addr->label = LABEL();
+label_addr->update_addr = update_addr;
+label_addr->next = common->label_addrs;
+common->label_addrs = label_addr;
+}
+
+static SLJIT_INLINE void count_match(compiler_common *common)
+{
+DEFINE_COMPILER;
+
+OP2(SLJIT_SUB | SLJIT_SET_Z, COUNT_MATCH, 0, COUNT_MATCH, 0, SLJIT_IMM, 1);
+add_jump(compiler, &common->calllimit, JUMP(SLJIT_ZERO));
+}
+
+static SLJIT_INLINE void allocate_stack(compiler_common *common, int size)
+{
+/* May destroy all locals and registers except TMP2. */
+DEFINE_COMPILER;
+
+SLJIT_ASSERT(size > 0);
+OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
+#ifdef DESTROY_REGISTERS
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 12345);
+OP1(SLJIT_MOV, TMP3, 0, TMP1, 0);
+OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, TMP1, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0);
+#endif
+add_stub(common, CMP(SLJIT_LESS, STACK_TOP, 0, STACK_LIMIT, 0));
+}
+
+static SLJIT_INLINE void free_stack(compiler_common *common, int size)
+{
+DEFINE_COMPILER;
+
+SLJIT_ASSERT(size > 0);
+OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, size * sizeof(sljit_sw));
+}
+
+static sljit_uw * allocate_read_only_data(compiler_common *common, sljit_uw size)
+{
+DEFINE_COMPILER;
+sljit_uw *result;
+
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+
+result = (sljit_uw *)SLJIT_MALLOC(size + sizeof(sljit_uw), compiler->allocator_data);
+if (SLJIT_UNLIKELY(result == NULL))
+ {
+ sljit_set_compiler_memory_error(compiler);
+ return NULL;
+ }
+
+*(void**)result = common->read_only_data_head;
+common->read_only_data_head = (void *)result;
+return result + 1;
+}
+
+static SLJIT_INLINE void reset_ovector(compiler_common *common, int length)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+sljit_s32 i;
+
+/* At this point we can freely use all temporary registers. */
+SLJIT_ASSERT(length > 1);
+/* TMP1 returns with begin - 1. */
+OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_S0), SLJIT_OFFSETOF(jit_arguments, begin), SLJIT_IMM, IN_UCHARS(1));
+if (length < 8)
+ {
+ for (i = 1; i < length; i++)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), SLJIT_R0, 0);
+ }
+else
+ {
+ if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)) == SLJIT_SUCCESS)
+ {
+ GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START);
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
+ loop = LABEL();
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
+ else
+ {
+ GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
+ loop = LABEL();
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R0, 0);
+ OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
+ }
+}
+
+static SLJIT_INLINE void reset_fast_fail(compiler_common *common)
+{
+DEFINE_COMPILER;
+sljit_s32 i;
+
+SLJIT_ASSERT(common->fast_fail_start_ptr < common->fast_fail_end_ptr);
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+for (i = common->fast_fail_start_ptr; i < common->fast_fail_end_ptr; i += sizeof(sljit_sw))
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), i, TMP1, 0);
+}
+
+static SLJIT_INLINE void do_reset_match(compiler_common *common, int length)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+int i;
+
+SLJIT_ASSERT(length > 1);
+/* OVECTOR(1) contains the "string begin - 1" constant. */
+if (length > 2)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+if (length < 8)
+ {
+ for (i = 2; i < length; i++)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(i), TMP1, 0);
+ }
+else
+ {
+ if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)) == SLJIT_SUCCESS)
+ {
+ GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
+ loop = LABEL();
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
+ else
+ {
+ GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
+ loop = LABEL();
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0);
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
+ }
+
+OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0);
+if (common->mark_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0);
+if (common->control_head_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack));
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, end));
+}
+
+static sljit_sw SLJIT_FUNC do_search_mark(sljit_sw *current, PCRE2_SPTR skip_arg)
+{
+while (current != NULL)
+ {
+ switch (current[1])
+ {
+ case type_then_trap:
+ break;
+
+ case type_mark:
+ if (PRIV(strcmp)(skip_arg, (PCRE2_SPTR)current[2]) == 0)
+ return current[3];
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]);
+ current = (sljit_sw*)current[0];
+ }
+return 0;
+}
+
+static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+BOOL has_pre;
+
+/* At this point we can freely use all registers. */
+OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(1), STR_PTR, 0);
+
+OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, SLJIT_S0, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+if (common->mark_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+OP1(SLJIT_MOV_U32, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, oveccount));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_S0, 0);
+if (common->mark_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0);
+OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, match_data),
+ SLJIT_IMM, SLJIT_OFFSETOF(pcre2_match_data, ovector) - sizeof(PCRE2_SIZE));
+
+has_pre = sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)) == SLJIT_SUCCESS;
+
+GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START - (has_pre ? sizeof(sljit_sw) : 0));
+OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, begin));
+
+loop = LABEL();
+
+if (has_pre)
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw));
+else
+ {
+ OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0);
+ OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw));
+ }
+
+OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, sizeof(PCRE2_SIZE));
+OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_R0, 0);
+/* Copy the integer value to the output buffer */
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+
+SLJIT_ASSERT(sizeof(PCRE2_SIZE) == 4 || sizeof(PCRE2_SIZE) == 8);
+OP1(((sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV), SLJIT_MEM1(SLJIT_R2), 0, SLJIT_S1, 0);
+
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+JUMPTO(SLJIT_NOT_ZERO, loop);
+
+/* Calculate the return value, which is the maximum ovector value. */
+if (topbracket > 1)
+ {
+ if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))) == SLJIT_SUCCESS)
+ {
+ GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
+
+ /* OVECTOR(0) is never equal to SLJIT_S2. */
+ loop = LABEL();
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw)));
+ OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+ CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0);
+ }
+ else
+ {
+ GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + (topbracket - 1) * 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
+
+ /* OVECTOR(0) is never equal to SLJIT_S2. */
+ loop = LABEL();
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), 0);
+ OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 2 * (sljit_sw)sizeof(sljit_sw));
+ OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+ CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0);
+ }
+ }
+else
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
+}
+
+static SLJIT_INLINE void return_with_partial_match(compiler_common *common, struct sljit_label *quit)
+{
+DEFINE_COMPILER;
+sljit_s32 mov_opcode;
+
+SLJIT_COMPILE_ASSERT(STR_END == SLJIT_S0, str_end_must_be_saved_reg0);
+SLJIT_ASSERT(common->start_used_ptr != 0 && common->start_ptr != 0
+ && (common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start != 0 : common->hit_start == 0));
+
+OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP),
+ common->mode == PCRE2_JIT_PARTIAL_SOFT ? common->hit_start : common->start_ptr);
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_PARTIAL);
+
+/* Store match begin and end. */
+OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, begin));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, startchar_ptr), SLJIT_R2, 0);
+OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, match_data));
+
+mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV;
+
+OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_S1, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector), SLJIT_R2, 0);
+
+OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_S1, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+OP2(SLJIT_ASHR, STR_END, 0, STR_END, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+OP1(mov_opcode, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(pcre2_match_data, ovector) + sizeof(PCRE2_SIZE), STR_END, 0);
+
+JUMPTO(SLJIT_JUMP, quit);
+}
+
+static SLJIT_INLINE void check_start_used_ptr(compiler_common *common)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+ {
+ /* The value of -1 must be kept for start_used_ptr! */
+ OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, 1);
+ /* Jumps if start_used_ptr < STR_PTR, or start_used_ptr == -1. Although overwriting
+ is not necessary if start_used_ptr == STR_PTR, it does not hurt as well. */
+ jump = CMP(SLJIT_LESS_EQUAL, TMP1, 0, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+else if (common->mode == PCRE2_JIT_PARTIAL_HARD)
+ {
+ jump = CMP(SLJIT_LESS_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+}
+
+static SLJIT_INLINE BOOL char_has_othercase(compiler_common *common, PCRE2_SPTR cc)
+{
+/* Detects if the character has an othercase. */
+unsigned int c;
+
+#ifdef SUPPORT_UNICODE
+if (common->utf)
+ {
+ GETCHAR(c, cc);
+ if (c > 127)
+ {
+ return c != UCD_OTHERCASE(c);
+ }
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ return common->fcc[c] != c;
+#endif
+ }
+else
+#endif
+ c = *cc;
+return MAX_255(c) ? common->fcc[c] != c : FALSE;
+}
+
+static SLJIT_INLINE unsigned int char_othercase(compiler_common *common, unsigned int c)
+{
+/* Returns with the othercase. */
+#ifdef SUPPORT_UNICODE
+if (common->utf && c > 127)
+ {
+ return UCD_OTHERCASE(c);
+ }
+#endif
+return TABLE_GET(c, common->fcc, c);
+}
+
+static unsigned int char_get_othercase_bit(compiler_common *common, PCRE2_SPTR cc)
+{
+/* Detects if the character and its othercase has only 1 bit difference. */
+unsigned int c, oc, bit;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+int n;
+#endif
+
+#ifdef SUPPORT_UNICODE
+if (common->utf)
+ {
+ GETCHAR(c, cc);
+ if (c <= 127)
+ oc = common->fcc[c];
+ else
+ {
+ oc = UCD_OTHERCASE(c);
+ }
+ }
+else
+ {
+ c = *cc;
+ oc = TABLE_GET(c, common->fcc, c);
+ }
+#else
+c = *cc;
+oc = TABLE_GET(c, common->fcc, c);
+#endif
+
+SLJIT_ASSERT(c != oc);
+
+bit = c ^ oc;
+/* Optimized for English alphabet. */
+if (c <= 127 && bit == 0x20)
+ return (0 << 8) | 0x20;
+
+/* Since c != oc, they must have at least 1 bit difference. */
+if (!is_powerof2(bit))
+ return 0;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+#ifdef SUPPORT_UNICODE
+if (common->utf && c > 127)
+ {
+ n = GET_EXTRALEN(*cc);
+ while ((bit & 0x3f) == 0)
+ {
+ n--;
+ bit >>= 6;
+ }
+ return (n << 8) | bit;
+ }
+#endif /* SUPPORT_UNICODE */
+return (0 << 8) | bit;
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+
+#ifdef SUPPORT_UNICODE
+if (common->utf && c > 65535)
+ {
+ if (bit >= (1 << 10))
+ bit >>= 10;
+ else
+ return (bit < 256) ? ((2 << 8) | bit) : ((3 << 8) | (bit >> 8));
+ }
+#endif /* SUPPORT_UNICODE */
+return (bit < 256) ? ((0 << 8) | bit) : ((1 << 8) | (bit >> 8));
+
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+}
+
+static void check_partial(compiler_common *common, BOOL force)
+{
+/* Checks whether a partial matching is occurred. Does not modify registers. */
+DEFINE_COMPILER;
+struct sljit_jump *jump = NULL;
+
+SLJIT_ASSERT(!force || common->mode != PCRE2_JIT_COMPLETE);
+
+if (common->mode == PCRE2_JIT_COMPLETE)
+ return;
+
+if (!force)
+ jump = CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+else if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+ jump = CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1);
+
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+else
+ {
+ if (common->partialmatchlabel != NULL)
+ JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+ else
+ add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+ }
+
+if (jump != NULL)
+ JUMPHERE(jump);
+}
+
+static void check_str_end(compiler_common *common, jump_list **end_reached)
+{
+/* Does not affect registers. Usually used in a tight spot. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == PCRE2_JIT_COMPLETE)
+ {
+ add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ return;
+ }
+
+jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+ {
+ add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+ add_jump(compiler, end_reached, JUMP(SLJIT_JUMP));
+ }
+else
+ {
+ add_jump(compiler, end_reached, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+ if (common->partialmatchlabel != NULL)
+ JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+ else
+ add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+ }
+JUMPHERE(jump);
+}
+
+static void detect_partial_match(compiler_common *common, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (common->mode == PCRE2_JIT_COMPLETE)
+ {
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ return;
+ }
+
+/* Partial matching mode. */
+jump = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0));
+if (common->mode == PCRE2_JIT_PARTIAL_SOFT)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ }
+else
+ {
+ if (common->partialmatchlabel != NULL)
+ JUMPTO(SLJIT_JUMP, common->partialmatchlabel);
+ else
+ add_jump(compiler, &common->partialmatch, JUMP(SLJIT_JUMP));
+ }
+JUMPHERE(jump);
+}
+
+static void peek_char(compiler_common *common, sljit_u32 max)
+{
+/* Reads the character into TMP1, keeps STR_PTR.
+Does not check STR_END. TMP2 Destroyed. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *jump;
+#endif
+
+SLJIT_UNUSED_ARG(max);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+ if (max < 128) return;
+
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ add_jump(compiler, &common->utfreadchar, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+ JUMPHERE(jump);
+ }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+ {
+ if (max < 0xd800) return;
+
+ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1);
+ /* TMP2 contains the high surrogate. */
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x40);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3ff);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ JUMPHERE(jump);
+ }
+#endif
+}
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+
+static BOOL is_char7_bitset(const sljit_u8 *bitset, BOOL nclass)
+{
+/* Tells whether the character codes below 128 are enough
+to determine a match. */
+const sljit_u8 value = nclass ? 0xff : 0;
+const sljit_u8 *end = bitset + 32;
+
+bitset += 16;
+do
+ {
+ if (*bitset++ != value)
+ return FALSE;
+ }
+while (bitset < end);
+return TRUE;
+}
+
+static void read_char7_type(compiler_common *common, BOOL full_read)
+{
+/* Reads the precise character type of a character into TMP1, if the character
+is less than 128. Otherwise it returns with zero. Does not check STR_END. The
+full_read argument tells whether characters above max are accepted or not. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+SLJIT_ASSERT(common->utf);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+
+if (full_read)
+ {
+ jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xc0);
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+ JUMPHERE(jump);
+ }
+}
+
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+
+static void read_char_range(compiler_common *common, sljit_u32 min, sljit_u32 max, BOOL update_str_ptr)
+{
+/* Reads the precise value of a character into TMP1, if the character is
+between min and max (c >= min && c <= max). Otherwise it returns with a value
+outside the range. Does not check STR_END. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *jump;
+#endif
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+struct sljit_jump *jump2;
+#endif
+
+SLJIT_UNUSED_ARG(update_str_ptr);
+SLJIT_UNUSED_ARG(min);
+SLJIT_UNUSED_ARG(max);
+SLJIT_ASSERT(min <= max);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+ if (max < 128 && !update_str_ptr) return;
+
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+ if (min >= 0x10000)
+ {
+ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xf0);
+ if (update_str_ptr)
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x7);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2));
+ if (!update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ JUMPHERE(jump2);
+ if (update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0);
+ }
+ else if (min >= 0x800 && max <= 0xffff)
+ {
+ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xe0);
+ if (update_str_ptr)
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xf);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ if (!update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ JUMPHERE(jump2);
+ if (update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0);
+ }
+ else if (max >= 0x800)
+ add_jump(compiler, (max < 0x10000) ? &common->utfreadchar16 : &common->utfreadchar, JUMP(SLJIT_FAST_CALL));
+ else if (max < 128)
+ {
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+ }
+ else
+ {
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (!update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ else
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ if (update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, RETURN_ADDR, 0);
+ }
+ JUMPHERE(jump);
+ }
+#endif
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+ {
+ if (max >= 0x10000)
+ {
+ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1);
+ /* TMP2 contains the high surrogate. */
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x40);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 10);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3ff);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+ JUMPHERE(jump);
+ return;
+ }
+
+ if (max < 0xd800 && !update_str_ptr) return;
+
+ /* Skip low surrogate if necessary. */
+ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1);
+ if (update_str_ptr)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ if (max >= 0xd800)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0x10000);
+ JUMPHERE(jump);
+ }
+#endif
+}
+
+static SLJIT_INLINE void read_char(compiler_common *common)
+{
+read_char_range(common, 0, READ_CHAR_MAX, TRUE);
+}
+
+static void read_char8_type(compiler_common *common, BOOL update_str_ptr)
+{
+/* Reads the character type into TMP1, updates STR_PTR. Does not check STR_END. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+struct sljit_jump *jump;
+#endif
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+struct sljit_jump *jump2;
+#endif
+
+SLJIT_UNUSED_ARG(update_str_ptr);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+ /* This can be an extra read in some situations, but hopefully
+ it is needed in most cases. */
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+ jump = CMP(SLJIT_LESS, TMP2, 0, SLJIT_IMM, 0xc0);
+ if (!update_str_ptr)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+ OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+ jump2 = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+ JUMPHERE(jump2);
+ }
+ else
+ add_jump(compiler, &common->utfreadtype8, JUMP(SLJIT_FAST_CALL));
+ JUMPHERE(jump);
+ return;
+ }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+/* The ctypes array contains only 256 values. */
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 255);
+#endif
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+JUMPHERE(jump);
+#endif
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf && update_str_ptr)
+ {
+ /* Skip low surrogate if necessary. */
+ OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xd800);
+ jump = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0xdc00 - 0xd800 - 1);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPHERE(jump);
+ }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16 */
+}
+
+static void skip_char_back(compiler_common *common)
+{
+/* Goes one character back. Affects STR_PTR and TMP1. Does not check begin. */
+DEFINE_COMPILER;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+struct sljit_label *label;
+
+if (common->utf)
+ {
+ label = LABEL();
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xc0);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0x80, label);
+ return;
+ }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -IN_UCHARS(1));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ /* Skip low surrogate if necessary. */
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xdc00);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ return;
+ }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+}
+
+static void check_newlinechar(compiler_common *common, int nltype, jump_list **backtracks, BOOL jumpifmatch)
+{
+/* Character comes in TMP1. Checks if it is a newline. TMP2 may be destroyed. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+if (nltype == NLTYPE_ANY)
+ {
+ add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(jumpifmatch ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ }
+else if (nltype == NLTYPE_ANYCRLF)
+ {
+ if (jumpifmatch)
+ {
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR));
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+ }
+ else
+ {
+ jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+ JUMPHERE(jump);
+ }
+ }
+else
+ {
+ SLJIT_ASSERT(nltype == NLTYPE_FIXED && common->newline < 256);
+ add_jump(compiler, backtracks, CMP(jumpifmatch ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
+ }
+}
+
+#ifdef SUPPORT_UNICODE
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+static void do_utfreadchar(compiler_common *common)
+{
+/* Fast decoding a UTF-8 character. TMP1 contains the first byte
+of the character (>= 0xc0). Return char value in TMP1, length in TMP2. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* Searching for the first zero. */
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Two byte sequence. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(2));
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x800);
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Three byte sequence. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(3));
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+
+/* Four byte sequence. */
+JUMPHERE(jump);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(2));
+OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x10000);
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(3));
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, IN_UCHARS(4));
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+static void do_utfreadchar16(compiler_common *common)
+{
+/* Fast decoding a UTF-8 character. TMP1 contains the first byte
+of the character (>= 0xc0). Return value in TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* Searching for the first zero. */
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x800);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Two byte sequence. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x400);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_NOT_ZERO);
+/* This code runs only in 8 bit mode. No need to shift the value. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+OP2(SLJIT_XOR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x800);
+OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP1, 0, TMP1, 0, TMP2, 0);
+/* Three byte sequence. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+static void do_utfreadtype8(compiler_common *common)
+{
+/* Fast decoding a UTF-8 character type. TMP2 contains the first byte
+of the character (>= 0xc0). Return value in TMP1. */
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_jump *compare;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, 0x20);
+jump = JUMP(SLJIT_NOT_ZERO);
+/* Two byte sequence. */
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0x1f);
+/* The upper 5 bits are known at this point. */
+compare = CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, 0x3);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 6);
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x3f);
+OP2(SLJIT_OR, TMP2, 0, TMP2, 0, TMP1, 0);
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP2), common->ctypes);
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+
+JUMPHERE(compare);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+
+/* We only have types for characters less than 256. */
+JUMPHERE(jump);
+OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+/* UCD_BLOCK_SIZE must be 128 (see the assert below). */
+#define UCD_BLOCK_MASK 127
+#define UCD_BLOCK_SHIFT 7
+
+static void do_getucd(compiler_common *common)
+{
+/* Search the UCD record for the character comes in TMP1.
+Returns chartype in TMP1 and UCD offset in TMP2. */
+DEFINE_COMPILER;
+#if PCRE2_CODE_UNIT_WIDTH == 32
+struct sljit_jump *jump;
+#endif
+
+#if defined SLJIT_DEBUG && SLJIT_DEBUG
+/* dummy_ucd_record */
+const ucd_record *record = GET_UCD(INVALID_UTF_CHAR);
+SLJIT_ASSERT(record->script == ucp_Common && record->chartype == ucp_Cn && record->gbprop == ucp_gbOther);
+SLJIT_ASSERT(record->caseset == 0 && record->other_case == 0);
+#endif
+
+SLJIT_ASSERT(UCD_BLOCK_SIZE == 128 && sizeof(ucd_record) == 8);
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+if (!common->utf)
+ {
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+ JUMPHERE(jump);
+ }
+#endif
+
+OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
+OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
+OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+#endif /* SUPPORT_UNICODE */
+
+static SLJIT_INLINE struct sljit_label *mainloop_entry(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *mainloop;
+struct sljit_label *newlinelabel = NULL;
+struct sljit_jump *start;
+struct sljit_jump *end = NULL;
+struct sljit_jump *end2 = NULL;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_jump *singlechar;
+#endif
+jump_list *newline = NULL;
+sljit_u32 overall_options = common->re->overall_options;
+BOOL hascrorlf = (common->re->flags & PCRE2_HASCRORLF) != 0;
+BOOL newlinecheck = FALSE;
+BOOL readuchar = FALSE;
+
+if (!(hascrorlf || (overall_options & PCRE2_FIRSTLINE) != 0)
+ && (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF || common->newline > 255))
+ newlinecheck = TRUE;
+
+SLJIT_ASSERT(common->abort_label == NULL);
+
+if ((overall_options & PCRE2_FIRSTLINE) != 0)
+ {
+ /* Search for the end of the first line. */
+ SLJIT_ASSERT(common->match_end_ptr != 0);
+ OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ mainloop = LABEL();
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, mainloop);
+ CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, mainloop);
+ JUMPHERE(end);
+ OP2(SLJIT_SUB, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+ else
+ {
+ end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ mainloop = LABEL();
+ /* Continual stores does not cause data dependency. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0);
+ read_char_range(common, common->nlmin, common->nlmax, TRUE);
+ check_newlinechar(common, common->nltype, &newline, TRUE);
+ CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, mainloop);
+ JUMPHERE(end);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, STR_PTR, 0);
+ set_jumps(newline, LABEL());
+ }
+
+ OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+ }
+else if ((overall_options & PCRE2_USE_OFFSET_LIMIT) != 0)
+ {
+ /* Check whether offset limit is set and valid. */
+ SLJIT_ASSERT(common->match_end_ptr != 0);
+
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, offset_limit));
+ OP1(SLJIT_MOV, TMP2, 0, STR_END, 0);
+ end = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (sljit_sw) PCRE2_UNSET);
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+#if PCRE2_CODE_UNIT_WIDTH == 16
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 2);
+#endif
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+ end2 = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
+ OP1(SLJIT_MOV, TMP2, 0, STR_END, 0);
+ JUMPHERE(end2);
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+ add_jump(compiler, &common->abort, CMP(SLJIT_LESS, TMP2, 0, STR_PTR, 0));
+ JUMPHERE(end);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr, TMP2, 0);
+ }
+
+start = JUMP(SLJIT_JUMP);
+
+if (newlinecheck)
+ {
+ newlinelabel = LABEL();
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ end = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, common->newline & 0xff);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ end2 = JUMP(SLJIT_JUMP);
+ }
+
+mainloop = LABEL();
+
+/* Increasing the STR_PTR here requires one less jump in the most common case. */
+#ifdef SUPPORT_UNICODE
+if (common->utf) readuchar = TRUE;
+#endif
+if (newlinecheck) readuchar = TRUE;
+
+if (readuchar)
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+
+if (newlinecheck)
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, newlinelabel);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+ singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ JUMPHERE(singlechar);
+ }
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (common->utf)
+ {
+ singlechar = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ JUMPHERE(singlechar);
+ }
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32 */
+JUMPHERE(start);
+
+if (newlinecheck)
+ {
+ JUMPHERE(end);
+ JUMPHERE(end2);
+ }
+
+return mainloop;
+}
+
+
+static SLJIT_INLINE void add_prefix_char(PCRE2_UCHAR chr, fast_forward_char_data *chars, BOOL last)
+{
+sljit_u32 i, count = chars->count;
+
+if (count == 255)
+ return;
+
+if (count == 0)
+ {
+ chars->count = 1;
+ chars->chars[0] = chr;
+
+ if (last)
+ chars->last_count = 1;
+ return;
+ }
+
+for (i = 0; i < count; i++)
+ if (chars->chars[i] == chr)
+ return;
+
+if (count >= MAX_DIFF_CHARS)
+ {
+ chars->count = 255;
+ return;
+ }
+
+chars->chars[count] = chr;
+chars->count = count + 1;
+
+if (last)
+ chars->last_count++;
+}
+
+static int scan_prefix(compiler_common *common, PCRE2_SPTR cc, fast_forward_char_data *chars, int max_chars, sljit_u32 *rec_count)
+{
+/* Recursive function, which scans prefix literals. */
+BOOL last, any, class, caseless;
+int len, repeat, len_save, consumed = 0;
+sljit_u32 chr; /* Any unicode character. */
+sljit_u8 *bytes, *bytes_end, byte;
+PCRE2_SPTR alternative, cc_save, oc;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+PCRE2_UCHAR othercase[4];
+#elif defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 16
+PCRE2_UCHAR othercase[2];
+#else
+PCRE2_UCHAR othercase[1];
+#endif
+
+repeat = 1;
+while (TRUE)
+ {
+ if (*rec_count == 0)
+ return 0;
+ (*rec_count)--;
+
+ last = TRUE;
+ any = FALSE;
+ class = FALSE;
+ caseless = FALSE;
+
+ switch (*cc)
+ {
+ case OP_CHARI:
+ caseless = TRUE;
+ /* Fall through */
+ case OP_CHAR:
+ last = FALSE;
+ cc++;
+ break;
+
+ case OP_SOD:
+ case OP_SOM:
+ case OP_SET_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ /* Zero width assertions. */
+ cc++;
+ continue;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ cc = bracketend(cc);
+ continue;
+
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ caseless = TRUE;
+ /* Fall through */
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ cc++;
+ break;
+
+ case OP_EXACTI:
+ caseless = TRUE;
+ /* Fall through */
+ case OP_EXACT:
+ repeat = GET2(cc, 1);
+ last = FALSE;
+ cc += 1 + IMM2_SIZE;
+ break;
+
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_POSQUERYI:
+ caseless = TRUE;
+ /* Fall through */
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_POSQUERY:
+ len = 1;
+ cc++;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
+#endif
+ max_chars = scan_prefix(common, cc + len, chars, max_chars, rec_count);
+ if (max_chars == 0)
+ return consumed;
+ last = FALSE;
+ break;
+
+ case OP_KET:
+ cc += 1 + LINK_SIZE;
+ continue;
+
+ case OP_ALT:
+ cc += GET(cc, 1);
+ continue;
+
+ case OP_ONCE:
+ case OP_BRA:
+ case OP_BRAPOS:
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ alternative = cc + GET(cc, 1);
+ while (*alternative == OP_ALT)
+ {
+ max_chars = scan_prefix(common, alternative + 1 + LINK_SIZE, chars, max_chars, rec_count);
+ if (max_chars == 0)
+ return consumed;
+ alternative += GET(alternative, 1);
+ }
+
+ if (*cc == OP_CBRA || *cc == OP_CBRAPOS)
+ cc += IMM2_SIZE;
+ cc += 1 + LINK_SIZE;
+ continue;
+
+ case OP_CLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)(cc + 1), FALSE))
+ return consumed;
+#endif
+ class = TRUE;
+ break;
+
+ case OP_NCLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf) return consumed;
+#endif
+ class = TRUE;
+ break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf) return consumed;
+#endif
+ any = TRUE;
+ cc += GET(cc, 1);
+ break;
+#endif
+
+ case OP_DIGIT:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_digit, FALSE))
+ return consumed;
+#endif
+ any = TRUE;
+ cc++;
+ break;
+
+ case OP_WHITESPACE:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_space, FALSE))
+ return consumed;
+#endif
+ any = TRUE;
+ cc++;
+ break;
+
+ case OP_WORDCHAR:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && !is_char7_bitset((const sljit_u8 *)common->ctypes - cbit_length + cbit_word, FALSE))
+ return consumed;
+#endif
+ any = TRUE;
+ cc++;
+ break;
+
+ case OP_NOT:
+ case OP_NOTI:
+ cc++;
+ /* Fall through. */
+ case OP_NOT_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf) return consumed;
+#endif
+ any = TRUE;
+ cc++;
+ break;
+
+#ifdef SUPPORT_UNICODE
+ case OP_NOTPROP:
+ case OP_PROP:
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf) return consumed;
+#endif
+ any = TRUE;
+ cc += 1 + 2;
+ break;
+#endif
+
+ case OP_TYPEEXACT:
+ repeat = GET2(cc, 1);
+ cc += 1 + IMM2_SIZE;
+ continue;
+
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf) return consumed;
+#endif
+ any = TRUE;
+ repeat = GET2(cc, 1);
+ cc += 1 + IMM2_SIZE + 1;
+ break;
+
+ default:
+ return consumed;
+ }
+
+ if (any)
+ {
+ do
+ {
+ chars->count = 255;
+
+ consumed++;
+ if (--max_chars == 0)
+ return consumed;
+ chars++;
+ }
+ while (--repeat > 0);
+
+ repeat = 1;
+ continue;
+ }
+
+ if (class)
+ {
+ bytes = (sljit_u8*) (cc + 1);
+ cc += 1 + 32 / sizeof(PCRE2_UCHAR);
+
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPOSSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSQUERY:
+ max_chars = scan_prefix(common, cc + 1, chars, max_chars, rec_count);
+ if (max_chars == 0)
+ return consumed;
+ break;
+
+ default:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ repeat = GET2(cc, 1);
+ if (repeat <= 0)
+ return consumed;
+ break;
+ }
+
+ do
+ {
+ if (bytes[31] & 0x80)
+ chars->count = 255;
+ else if (chars->count != 255)
+ {
+ bytes_end = bytes + 32;
+ chr = 0;
+ do
+ {
+ byte = *bytes++;
+ SLJIT_ASSERT((chr & 0x7) == 0);
+ if (byte == 0)
+ chr += 8;
+ else
+ {
+ do
+ {
+ if ((byte & 0x1) != 0)
+ add_prefix_char(chr, chars, TRUE);
+ byte >>= 1;
+ chr++;
+ }
+ while (byte != 0);
+ chr = (chr + 7) & ~7;
+ }
+ }
+ while (chars->count != 255 && bytes < bytes_end);
+ bytes = bytes_end - 32;
+ }
+
+ consumed++;
+ if (--max_chars == 0)
+ return consumed;
+ chars++;
+ }
+ while (--repeat > 0);
+
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPOSSTAR:
+ return consumed;
+
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSQUERY:
+ cc++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ if (GET2(cc, 1) != GET2(cc, 1 + IMM2_SIZE))
+ return consumed;
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+ }
+
+ repeat = 1;
+ continue;
+ }
+
+ len = 1;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(*cc)) len += GET_EXTRALEN(*cc);
+#endif
+
+ if (caseless && char_has_othercase(common, cc))
+ {
+#ifdef SUPPORT_UNICODE
+ if (common->utf)
+ {
+ GETCHAR(chr, cc);
+ if ((int)PRIV(ord2utf)(char_othercase(common, chr), othercase) != len)
+ return consumed;
+ }
+ else
+#endif
+ {
+ chr = *cc;
+ othercase[0] = TABLE_GET(chr, common->fcc, chr);
+ }
+ }
+ else
+ {
+ caseless = FALSE;
+ othercase[0] = 0; /* Stops compiler warning - PH */
+ }
+
+ len_save = len;
+ cc_save = cc;
+ while (TRUE)
+ {
+ oc = othercase;
+ do
+ {
+ len--;
+ consumed++;
+
+ chr = *cc;
+ add_prefix_char(*cc, chars, len == 0);
+
+ if (caseless)
+ add_prefix_char(*oc, chars, len == 0);
+
+ if (--max_chars == 0)
+ return consumed;
+ chars++;
+ cc++;
+ oc++;
+ }
+ while (len > 0);
+
+ if (--repeat == 0)
+ break;
+
+ len = len_save;
+ cc = cc_save;
+ }
+
+ repeat = 1;
+ if (last)
+ return consumed;
+ }
+}
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+static void jumpto_if_not_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg, struct sljit_label *label)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0);
+CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0x80, label);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00);
+CMPTO(SLJIT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00, label);
+#else
+#error "Unknown code width"
+#endif
+}
+#endif
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND)
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+static struct sljit_jump *jump_if_utf_char_start(struct sljit_compiler *compiler, sljit_s32 reg)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xc0);
+return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0x80);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+OP2(SLJIT_AND, reg, 0, reg, 0, SLJIT_IMM, 0xfc00);
+return CMP(SLJIT_NOT_EQUAL, reg, 0, SLJIT_IMM, 0xdc00);
+#else
+#error "Unknown code width"
+#endif
+}
+#endif
+
+static sljit_s32 character_to_int32(PCRE2_UCHAR chr)
+{
+sljit_s32 value = (sljit_s32)chr;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#define SSE2_COMPARE_TYPE_INDEX 0
+return (value << 24) | (value << 16) | (value << 8) | value;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#define SSE2_COMPARE_TYPE_INDEX 1
+return (value << 16) | value;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+#define SSE2_COMPARE_TYPE_INDEX 2
+return value;
+#else
+#error "Unsupported unit width"
+#endif
+}
+
+static void load_from_mem_sse2(struct sljit_compiler *compiler, sljit_s32 dst_xmm_reg, sljit_s32 src_general_reg)
+{
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+sljit_u8 instruction[5];
+#else
+sljit_u8 instruction[4];
+#endif
+
+SLJIT_ASSERT(dst_xmm_reg < 8);
+
+/* MOVDQA xmm1, xmm2/m128 */
+#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
+if (src_general_reg < 8)
+ {
+ instruction[0] = 0x66;
+ instruction[1] = 0x0f;
+ instruction[2] = 0x6f;
+ instruction[3] = (dst_xmm_reg << 3) | src_general_reg;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+else
+ {
+ instruction[0] = 0x66;
+ instruction[1] = 0x41;
+ instruction[2] = 0x0f;
+ instruction[3] = 0x6f;
+ instruction[4] = (dst_xmm_reg << 3) | (src_general_reg & 0x7);
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+#else
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6f;
+instruction[3] = (dst_xmm_reg << 3) | src_general_reg;
+sljit_emit_op_custom(compiler, instruction, 4);
+#endif
+}
+
+static void fast_forward_char_pair_sse2_compare(struct sljit_compiler *compiler, PCRE2_UCHAR char1, PCRE2_UCHAR char2,
+ sljit_u32 bit, sljit_s32 dst_ind, sljit_s32 cmp1_ind, sljit_s32 cmp2_ind, sljit_s32 tmp_ind)
+{
+sljit_u8 instruction[4];
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+
+if (char1 == char2 || bit != 0)
+ {
+ if (bit != 0)
+ {
+ /* POR xmm1, xmm2/m128 */
+ /* instruction[0] = 0x66; */
+ /* instruction[1] = 0x0f; */
+ instruction[2] = 0xeb;
+ instruction[3] = 0xc0 | (dst_ind << 3) | cmp2_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+ /* PCMPEQB/W/D xmm1, xmm2/m128 */
+ /* instruction[0] = 0x66; */
+ /* instruction[1] = 0x0f; */
+ instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+ instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+else
+ {
+ /* MOVDQA xmm1, xmm2/m128 */
+ /* instruction[0] = 0x66; */
+ /* instruction[1] = 0x0f; */
+ instruction[2] = 0x6f;
+ instruction[3] = 0xc0 | (tmp_ind << 3) | dst_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+
+ /* PCMPEQB/W/D xmm1, xmm2/m128 */
+ /* instruction[0] = 0x66; */
+ /* instruction[1] = 0x0f; */
+ instruction[2] = 0x74 + SSE2_COMPARE_TYPE_INDEX;
+ instruction[3] = 0xc0 | (dst_ind << 3) | cmp1_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+
+ instruction[3] = 0xc0 | (tmp_ind << 3) | cmp2_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+
+ /* POR xmm1, xmm2/m128 */
+ /* instruction[0] = 0x66; */
+ /* instruction[1] = 0x0f; */
+ instruction[2] = 0xeb;
+ instruction[3] = 0xc0 | (dst_ind << 3) | tmp_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+}
+
+static void fast_forward_first_char2_sse2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *quit;
+struct sljit_jump *partial_quit[2];
+sljit_u8 instruction[8];
+sljit_s32 tmp1_ind = sljit_get_register_index(TMP1);
+sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 data_ind = 0;
+sljit_s32 tmp_ind = 1;
+sljit_s32 cmp1_ind = 2;
+sljit_s32 cmp2_ind = 3;
+sljit_u32 bit = 0;
+
+SLJIT_UNUSED_ARG(offset);
+
+if (char1 != char2)
+ {
+ bit = char1 ^ char2;
+ if (!is_powerof2(bit))
+ bit = 0;
+ }
+
+partial_quit[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, &common->failed_match, partial_quit[0]);
+
+/* First part (unaligned start) */
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1 | bit));
+
+SLJIT_ASSERT(tmp1_ind < 8);
+
+/* MOVD xmm, r/m32 */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6e;
+instruction[3] = 0xc0 | (cmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char1 != char2)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(bit != 0 ? bit : char2));
+
+ /* MOVD xmm, r/m32 */
+ instruction[3] = 0xc0 | (cmp2_ind << 3) | tmp1_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+
+/* PSHUFD xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x70;
+instruction[3] = 0xc0 | (cmp1_ind << 3) | 2;
+instruction[4] = 0;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char1 != char2)
+ {
+ /* PSHUFD xmm1, xmm2/m128, imm8 */
+ instruction[3] = 0xc0 | (cmp2_ind << 3) | 3;
+ sljit_emit_op_custom(compiler, instruction, 5);
+ }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+
+load_from_mem_sse2(compiler, data_ind, str_ptr_ind);
+fast_forward_char_pair_sse2_compare(compiler, char1, char2, bit, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+sljit_set_current_flags(compiler, SLJIT_SET_Z);
+
+quit = JUMP(SLJIT_NOT_ZERO);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+start = LABEL();
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+
+partial_quit[1] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, &common->failed_match, partial_quit[1]);
+
+/* Second part (aligned) */
+
+load_from_mem_sse2(compiler, 0, str_ptr_ind);
+fast_forward_char_pair_sse2_compare(compiler, char1, char2, bit, data_ind, cmp1_ind, cmp2_ind, tmp_ind);
+
+/* PMOVMSKB reg, xmm */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+sljit_set_current_flags(compiler, SLJIT_SET_Z);
+
+JUMPTO(SLJIT_ZERO, start);
+
+JUMPHERE(quit);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+ {
+ JUMPHERE(partial_quit[0]);
+ JUMPHERE(partial_quit[1]);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_PTR, 0, STR_END, 0);
+ CMOV(SLJIT_GREATER, STR_PTR, STR_END, 0);
+ }
+else
+ add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset > 0)
+ {
+ SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
+
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offset));
+
+ quit = jump_if_utf_char_start(compiler, TMP1);
+
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, restart);
+
+ JUMPHERE(quit);
+ }
+#endif
+}
+
+#ifndef _WIN64
+
+static SLJIT_INLINE sljit_u32 max_fast_forward_char_pair_sse2_offset(void)
+{
+#if PCRE2_CODE_UNIT_WIDTH == 8
+return 15;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+return 7;
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+return 3;
+#else
+#error "Unsupported unit width"
+#endif
+}
+
+static void fast_forward_char_pair_sse2(compiler_common *common, sljit_s32 offs1,
+ PCRE2_UCHAR char1a, PCRE2_UCHAR char1b, sljit_s32 offs2, PCRE2_UCHAR char2a, PCRE2_UCHAR char2b)
+{
+DEFINE_COMPILER;
+sljit_u32 bit1 = 0;
+sljit_u32 bit2 = 0;
+sljit_u32 diff = IN_UCHARS(offs1 - offs2);
+sljit_s32 tmp1_ind = sljit_get_register_index(TMP1);
+sljit_s32 tmp2_ind = sljit_get_register_index(TMP2);
+sljit_s32 str_ptr_ind = sljit_get_register_index(STR_PTR);
+sljit_s32 data1_ind = 0;
+sljit_s32 data2_ind = 1;
+sljit_s32 tmp_ind = 2;
+sljit_s32 cmp1a_ind = 3;
+sljit_s32 cmp1b_ind = 4;
+sljit_s32 cmp2a_ind = 5;
+sljit_s32 cmp2b_ind = 6;
+struct sljit_label *start;
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+struct sljit_label *restart;
+#endif
+struct sljit_jump *jump[2];
+
+sljit_u8 instruction[8];
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE && offs1 > offs2);
+SLJIT_ASSERT(diff <= IN_UCHARS(max_fast_forward_char_pair_sse2_offset()));
+SLJIT_ASSERT(tmp1_ind < 8 && tmp2_ind == 1);
+
+/* Initialize. */
+if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offs1 + 1));
+
+ OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP1, 0, STR_END, 0);
+ CMOV(SLJIT_LESS, STR_END, TMP1, 0);
+ }
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+/* MOVD xmm, r/m32 */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+instruction[2] = 0x6e;
+
+if (char1a == char1b)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
+else
+ {
+ bit1 = char1a ^ char1b;
+ if (is_powerof2(bit1))
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a | bit1));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit1));
+ }
+ else
+ {
+ bit1 = 0;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char1a));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char1b));
+ }
+ }
+
+instruction[3] = 0xc0 | (cmp1a_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char1a != char1b)
+ {
+ instruction[3] = 0xc0 | (cmp1b_ind << 3) | tmp2_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+if (char2a == char2b)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
+else
+ {
+ bit2 = char2a ^ char2b;
+ if (is_powerof2(bit2))
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a | bit2));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(bit2));
+ }
+ else
+ {
+ bit2 = 0;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, character_to_int32(char2a));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, character_to_int32(char2b));
+ }
+ }
+
+instruction[3] = 0xc0 | (cmp2a_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+if (char2a != char2b)
+ {
+ instruction[3] = 0xc0 | (cmp2b_ind << 3) | tmp2_ind;
+ sljit_emit_op_custom(compiler, instruction, 4);
+ }
+
+/* PSHUFD xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x70;
+instruction[4] = 0;
+
+instruction[3] = 0xc0 | (cmp1a_ind << 3) | cmp1a_ind;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char1a != char1b)
+ {
+ instruction[3] = 0xc0 | (cmp1b_ind << 3) | cmp1b_ind;
+ sljit_emit_op_custom(compiler, instruction, 5);
+ }
+
+instruction[3] = 0xc0 | (cmp2a_ind << 3) | cmp2a_ind;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+if (char2a != char2b)
+ {
+ instruction[3] = 0xc0 | (cmp2b_ind << 3) | cmp2b_ind;
+ sljit_emit_op_custom(compiler, instruction, 5);
+ }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+restart = LABEL();
+#endif
+
+OP2(SLJIT_SUB, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1 - offs2));
+OP1(SLJIT_MOV, TMP2, 0, STR_PTR, 0);
+OP2(SLJIT_AND, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, ~0xf);
+OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, ~0xf);
+
+load_from_mem_sse2(compiler, data1_ind, str_ptr_ind);
+
+jump[0] = CMP(SLJIT_EQUAL, STR_PTR, 0, TMP1, 0);
+
+load_from_mem_sse2(compiler, data2_ind, tmp1_ind);
+
+/* MOVDQA xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x6f;
+instruction[3] = 0xc0 | (tmp_ind << 3) | data1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PSLLDQ xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x73;
+instruction[3] = 0xc0 | (7 << 3) | tmp_ind;
+instruction[4] = diff;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+/* PSRLDQ xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+/* instruction[2] = 0x73; */
+instruction[3] = 0xc0 | (3 << 3) | data2_ind;
+instruction[4] = 16 - diff;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+/* POR xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xeb;
+instruction[3] = 0xc0 | (data2_ind << 3) | tmp_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+jump[1] = JUMP(SLJIT_JUMP);
+
+JUMPHERE(jump[0]);
+
+/* MOVDQA xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x6f;
+instruction[3] = 0xc0 | (data2_ind << 3) | data1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PSLLDQ xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x73;
+instruction[3] = 0xc0 | (7 << 3) | data2_ind;
+instruction[4] = diff;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+JUMPHERE(jump[1]);
+
+OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 0xf);
+
+fast_forward_char_pair_sse2_compare(compiler, char2a, char2b, bit2, data2_ind, cmp2a_ind, cmp2b_ind, tmp_ind);
+fast_forward_char_pair_sse2_compare(compiler, char1a, char1b, bit1, data1_ind, cmp1a_ind, cmp1b_ind, tmp_ind);
+
+/* PAND xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xdb;
+instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* Ignore matches before the first STR_PTR. */
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, TMP2, 0);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+sljit_set_current_flags(compiler, SLJIT_SET_Z);
+
+jump[0] = JUMP(SLJIT_NOT_ZERO);
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+/* Main loop. */
+instruction[0] = 0x66;
+instruction[1] = 0x0f;
+
+start = LABEL();
+
+load_from_mem_sse2(compiler, data2_ind, str_ptr_ind);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, 16);
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+load_from_mem_sse2(compiler, data1_ind, str_ptr_ind);
+
+/* PSRLDQ xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x73;
+instruction[3] = 0xc0 | (3 << 3) | data2_ind;
+instruction[4] = 16 - diff;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+/* MOVDQA xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x6f;
+instruction[3] = 0xc0 | (tmp_ind << 3) | data1_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PSLLDQ xmm1, xmm2/m128, imm8 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0x73;
+instruction[3] = 0xc0 | (7 << 3) | tmp_ind;
+instruction[4] = diff;
+sljit_emit_op_custom(compiler, instruction, 5);
+
+/* POR xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xeb;
+instruction[3] = 0xc0 | (data2_ind << 3) | tmp_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+fast_forward_char_pair_sse2_compare(compiler, char1a, char1b, bit1, data1_ind, cmp1a_ind, cmp1b_ind, tmp_ind);
+fast_forward_char_pair_sse2_compare(compiler, char2a, char2b, bit2, data2_ind, cmp2a_ind, cmp2b_ind, tmp_ind);
+
+/* PAND xmm1, xmm2/m128 */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xdb;
+instruction[3] = 0xc0 | (data1_ind << 3) | data2_ind;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* PMOVMSKB reg, xmm */
+/* instruction[0] = 0x66; */
+/* instruction[1] = 0x0f; */
+instruction[2] = 0xd7;
+instruction[3] = 0xc0 | (tmp1_ind << 3) | 0;
+sljit_emit_op_custom(compiler, instruction, 4);
+
+/* BSF r32, r/m32 */
+instruction[0] = 0x0f;
+instruction[1] = 0xbc;
+instruction[2] = 0xc0 | (tmp1_ind << 3) | tmp1_ind;
+sljit_emit_op_custom(compiler, instruction, 3);
+sljit_set_current_flags(compiler, SLJIT_SET_Z);
+
+JUMPTO(SLJIT_ZERO, start);
+
+JUMPHERE(jump[0]);
+
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-offs1));
+
+ jump[0] = jump_if_utf_char_start(compiler, TMP1);
+
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, restart);
+
+ add_jump(compiler, &common->failed_match, JUMP(SLJIT_JUMP));
+
+ JUMPHERE(jump[0]);
+ }
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offs1));
+
+if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+static BOOL check_fast_forward_char_pair_sse2(compiler_common *common, fast_forward_char_data *chars, int max)
+{
+sljit_s32 i, j, priority, count;
+sljit_u32 priorities;
+PCRE2_UCHAR a1, a2, b1, b2;
+
+priorities = 0;
+
+count = 0;
+for (i = 0; i < max; i++)
+ {
+ if (chars[i].last_count > 2)
+ {
+ SLJIT_ASSERT(chars[i].last_count <= 7);
+
+ priorities |= (1 << chars[i].last_count);
+ count++;
+ }
+ }
+
+if (count < 2)
+ return FALSE;
+
+for (priority = 7; priority > 2; priority--)
+ {
+ if ((priorities & (1 << priority)) == 0)
+ continue;
+
+ for (i = max - 1; i >= 1; i--)
+ if (chars[i].last_count >= priority)
+ {
+ SLJIT_ASSERT(chars[i].count <= 2 && chars[i].count >= 1);
+
+ a1 = chars[i].chars[0];
+ a2 = chars[i].chars[1];
+
+ j = i - max_fast_forward_char_pair_sse2_offset();
+ if (j < 0)
+ j = 0;
+
+ while (j < i)
+ {
+ if (chars[j].last_count >= priority)
+ {
+ b1 = chars[j].chars[0];
+ b2 = chars[j].chars[1];
+
+ if (a1 != b1 && a1 != b2 && a2 != b1 && a2 != b2)
+ {
+ fast_forward_char_pair_sse2(common, i, a1, a2, j, b1, b2);
+ return TRUE;
+ }
+ }
+ j++;
+ }
+ }
+ }
+
+return FALSE;
+}
+
+#endif
+
+#undef SSE2_COMPARE_TYPE_INDEX
+
+#endif
+
+static void fast_forward_first_char2(compiler_common *common, PCRE2_UCHAR char1, PCRE2_UCHAR char2, sljit_s32 offset)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *match;
+struct sljit_jump *partial_quit;
+PCRE2_UCHAR mask;
+BOOL has_match_end = (common->match_end_ptr != 0);
+
+SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE || offset == 0);
+
+if (has_match_end)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+
+if (offset > 0)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+
+if (has_match_end)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(offset + 1));
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0);
+ CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+ }
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND)
+
+/* SSE2 accelerated first character search. */
+
+if (sljit_has_cpu_feature(SLJIT_HAS_SSE2))
+ {
+ fast_forward_first_char2_sse2(common, char1, char2, offset);
+
+ if (offset > 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset));
+
+ if (has_match_end)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+ return;
+ }
+
+#endif
+
+start = LABEL();
+
+partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, &common->failed_match, partial_quit);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (char1 == char2)
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1, start);
+else
+ {
+ mask = char1 ^ char2;
+ if (is_powerof2(mask))
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char1 | mask, start);
+ }
+ else
+ {
+ match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, char1);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, char2, start);
+ JUMPHERE(match);
+ }
+ }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset > 0)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-(offset + 1)));
+ jumpto_if_not_utf_char_start(compiler, TMP1, start);
+ }
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(offset + 1));
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+ JUMPHERE(partial_quit);
+
+if (has_match_end)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+static SLJIT_INLINE BOOL fast_forward_first_n_chars(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *start;
+struct sljit_jump *match;
+fast_forward_char_data chars[MAX_N_CHARS];
+sljit_s32 offset;
+PCRE2_UCHAR mask;
+PCRE2_UCHAR *char_set, *char_set_end;
+int i, max, from;
+int range_right = -1, range_len;
+sljit_u8 *update_table = NULL;
+BOOL in_range;
+sljit_u32 rec_count;
+
+for (i = 0; i < MAX_N_CHARS; i++)
+ {
+ chars[i].count = 0;
+ chars[i].last_count = 0;
+ }
+
+rec_count = 10000;
+max = scan_prefix(common, common->start, chars, MAX_N_CHARS, &rec_count);
+
+if (max < 1)
+ return FALSE;
+
+/* Convert last_count to priority. */
+for (i = 0; i < max; i++)
+ {
+ SLJIT_ASSERT(chars[i].count > 0 && chars[i].last_count <= chars[i].count);
+
+ if (chars[i].count == 1)
+ {
+ chars[i].last_count = (chars[i].last_count == 1) ? 7 : 5;
+ /* Simplifies algorithms later. */
+ chars[i].chars[1] = chars[i].chars[0];
+ }
+ else if (chars[i].count == 2)
+ {
+ SLJIT_ASSERT(chars[i].chars[0] != chars[i].chars[1]);
+
+ if (is_powerof2(chars[i].chars[0] ^ chars[i].chars[1]))
+ chars[i].last_count = (chars[i].last_count == 2) ? 6 : 4;
+ else
+ chars[i].last_count = (chars[i].last_count == 2) ? 3 : 2;
+ }
+ else
+ chars[i].last_count = (chars[i].count == 255) ? 0 : 1;
+ }
+
+#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86) && !(defined SUPPORT_VALGRIND) && !(defined _WIN64)
+if (check_fast_forward_char_pair_sse2(common, chars, max))
+ return TRUE;
+#endif
+
+in_range = FALSE;
+/* Prevent compiler "uninitialized" warning */
+from = 0;
+range_len = 4 /* minimum length */ - 1;
+for (i = 0; i <= max; i++)
+ {
+ if (in_range && (i - from) > range_len && (chars[i - 1].count < 255))
+ {
+ range_len = i - from;
+ range_right = i - 1;
+ }
+
+ if (i < max && chars[i].count < 255)
+ {
+ SLJIT_ASSERT(chars[i].count > 0);
+ if (!in_range)
+ {
+ in_range = TRUE;
+ from = i;
+ }
+ }
+ else
+ in_range = FALSE;
+ }
+
+if (range_right >= 0)
+ {
+ update_table = (sljit_u8 *)allocate_read_only_data(common, 256);
+ if (update_table == NULL)
+ return TRUE;
+ memset(update_table, IN_UCHARS(range_len), 256);
+
+ for (i = 0; i < range_len; i++)
+ {
+ SLJIT_ASSERT(chars[range_right - i].count > 0 && chars[range_right - i].count < 255);
+
+ char_set = chars[range_right - i].chars;
+ char_set_end = char_set + chars[range_right - i].count;
+ do
+ {
+ if (update_table[(*char_set) & 0xff] > IN_UCHARS(i))
+ update_table[(*char_set) & 0xff] = IN_UCHARS(i);
+ char_set++;
+ }
+ while (char_set < char_set_end);
+ }
+ }
+
+offset = -1;
+/* Scan forward. */
+for (i = 0; i < max; i++)
+ {
+ if (range_right == i)
+ continue;
+
+ if (offset == -1)
+ {
+ if (chars[i].last_count >= 2)
+ offset = i;
+ }
+ else if (chars[offset].last_count < chars[i].last_count)
+ offset = i;
+ }
+
+SLJIT_ASSERT(offset == -1 || (chars[offset].count >= 1 && chars[offset].count <= 2));
+
+if (range_right < 0)
+ {
+ if (offset < 0)
+ return FALSE;
+ /* Works regardless the value is 1 or 2. */
+ fast_forward_first_char2(common, chars[offset].chars[0], chars[offset].chars[1], offset);
+ return TRUE;
+ }
+
+SLJIT_ASSERT(range_right != offset);
+
+if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+ OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0);
+ CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+ }
+else
+ OP2(SLJIT_SUB, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+
+SLJIT_ASSERT(range_right >= 0);
+
+#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+OP1(SLJIT_MOV, RETURN_ADDR, 0, SLJIT_IMM, (sljit_sw)update_table);
+#endif
+
+start = LABEL();
+add_jump(compiler, &common->failed_match, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
+
+#if PCRE2_CODE_UNIT_WIDTH == 8 || (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right));
+#else
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(range_right + 1) - 1);
+#endif
+
+#if !(defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(RETURN_ADDR, TMP1), 0);
+#else
+OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)update_table);
+#endif
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, start);
+
+if (offset >= 0)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(offset));
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ if (chars[offset].count == 1)
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0], start);
+ else
+ {
+ mask = chars[offset].chars[0] ^ chars[offset].chars[1];
+ if (is_powerof2(mask))
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, mask);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0] | mask, start);
+ }
+ else
+ {
+ match = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[0]);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, chars[offset].chars[1], start);
+ JUMPHERE(match);
+ }
+ }
+ }
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+if (common->utf && offset != 0)
+ {
+ if (offset < 0)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+ else
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+
+ jumpto_if_not_utf_char_start(compiler, TMP1, start);
+
+ if (offset < 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+#endif
+
+if (offset >= 0)
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+else
+ OP2(SLJIT_ADD, STR_END, 0, STR_END, 0, SLJIT_IMM, IN_UCHARS(max));
+return TRUE;
+}
+
+static SLJIT_INLINE void fast_forward_first_char(compiler_common *common)
+{
+PCRE2_UCHAR first_char = (PCRE2_UCHAR)(common->re->first_codeunit);
+PCRE2_UCHAR oc;
+
+oc = first_char;
+if ((common->re->flags & PCRE2_FIRSTCASELESS) != 0)
+ {
+ oc = TABLE_GET(first_char, common->fcc, first_char);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (first_char > 127 && common->utf)
+ oc = UCD_OTHERCASE(first_char);
+#endif
+ }
+
+fast_forward_first_char2(common, first_char, oc, 0);
+}
+
+static SLJIT_INLINE void fast_forward_newline(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+struct sljit_jump *lastchar;
+struct sljit_jump *firstchar;
+struct sljit_jump *quit;
+struct sljit_jump *foundcr = NULL;
+struct sljit_jump *notfoundnl;
+jump_list *newline = NULL;
+
+if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+ OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ }
+
+if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, STR_PTR, 0, TMP1, 0);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+ loop = LABEL();
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff, loop);
+ CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff, loop);
+
+ JUMPHERE(quit);
+ JUMPHERE(firstchar);
+ JUMPHERE(lastchar);
+
+ if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+ return;
+ }
+
+OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+firstchar = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+skip_char_back(common);
+
+loop = LABEL();
+common->ff_newline_shortcut = loop;
+
+read_char_range(common, common->nlmin, common->nlmax, TRUE);
+lastchar = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
+ foundcr = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+check_newlinechar(common, common->nltype, &newline, FALSE);
+set_jumps(newline, loop);
+
+if (common->nltype == NLTYPE_ANY || common->nltype == NLTYPE_ANYCRLF)
+ {
+ quit = JUMP(SLJIT_JUMP);
+ JUMPHERE(foundcr);
+ notfoundnl = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, CHAR_NL);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+#if PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, UCHAR_SHIFT);
+#endif
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ JUMPHERE(notfoundnl);
+ JUMPHERE(quit);
+ }
+JUMPHERE(lastchar);
+JUMPHERE(firstchar);
+
+if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+}
+
+static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks);
+
+static SLJIT_INLINE void fast_forward_start_bits(compiler_common *common)
+{
+DEFINE_COMPILER;
+const sljit_u8 *start_bits = common->re->start_bitmap;
+struct sljit_label *start;
+struct sljit_jump *partial_quit;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+struct sljit_jump *found = NULL;
+#endif
+jump_list *matches = NULL;
+
+if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, STR_END, 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, STR_END, 0, TMP1, 0);
+ CMOV(SLJIT_GREATER, STR_END, TMP1, 0);
+ }
+
+start = LABEL();
+
+partial_quit = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, &common->failed_match, partial_quit);
+
+OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (!optimize_class(common, start_bits, (start_bits[31] & 0x80) != 0, FALSE, &matches))
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if ((start_bits[31] & 0x80) != 0)
+ found = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255);
+ else
+ CMPTO(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 255, start);
+#elif defined SUPPORT_UNICODE
+ if (common->utf && is_char7_bitset(start_bits, FALSE))
+ CMPTO(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 127, start);
+#endif
+ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+ OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)start_bits);
+ if (sljit_get_register_index(TMP3) >= 0)
+ {
+ OP2(SLJIT_SHL, TMP3, 0, SLJIT_IMM, 1, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP3, 0);
+ }
+ else
+ {
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ }
+ JUMPTO(SLJIT_ZERO, start);
+ }
+else
+ set_jumps(matches, start);
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+if (found != NULL)
+ JUMPHERE(found);
+#endif
+
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (common->mode != PCRE2_JIT_COMPLETE)
+ JUMPHERE(partial_quit);
+
+if (common->match_end_ptr != 0)
+ OP1(SLJIT_MOV, STR_END, 0, RETURN_ADDR, 0);
+}
+
+static SLJIT_INLINE struct sljit_jump *search_requested_char(compiler_common *common, PCRE2_UCHAR req_char, BOOL caseless, BOOL has_firstchar)
+{
+DEFINE_COMPILER;
+struct sljit_label *loop;
+struct sljit_jump *toolong;
+struct sljit_jump *alreadyfound;
+struct sljit_jump *found;
+struct sljit_jump *foundoc = NULL;
+struct sljit_jump *notfound;
+sljit_u32 oc, bit;
+
+SLJIT_ASSERT(common->req_char_ptr != 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr);
+OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, REQ_CU_MAX);
+toolong = CMP(SLJIT_LESS, TMP1, 0, STR_END, 0);
+alreadyfound = CMP(SLJIT_LESS, STR_PTR, 0, TMP2, 0);
+
+if (has_firstchar)
+ OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+else
+ OP1(SLJIT_MOV, TMP1, 0, STR_PTR, 0);
+
+loop = LABEL();
+notfound = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, STR_END, 0);
+
+OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(TMP1), 0);
+oc = req_char;
+if (caseless)
+ {
+ oc = TABLE_GET(req_char, common->fcc, req_char);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (req_char > 127 && common->utf)
+ oc = UCD_OTHERCASE(req_char);
+#endif
+ }
+if (req_char == oc)
+ found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char);
+else
+ {
+ bit = req_char ^ oc;
+ if (is_powerof2(bit))
+ {
+ OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, bit);
+ found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char | bit);
+ }
+ else
+ {
+ found = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, req_char);
+ foundoc = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, oc);
+ }
+ }
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+JUMPTO(SLJIT_JUMP, loop);
+
+JUMPHERE(found);
+if (foundoc)
+ JUMPHERE(foundoc);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, TMP1, 0);
+JUMPHERE(alreadyfound);
+JUMPHERE(toolong);
+return notfound;
+}
+
+static void do_revertframes(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *mainloop;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+GET_LOCAL_BASE(TMP1, 0, 0);
+
+/* Drop frames until we reach STACK_TOP. */
+mainloop = LABEL();
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), -sizeof(sljit_sw));
+jump = CMP(SLJIT_SIG_LESS_EQUAL, TMP2, 0, SLJIT_IMM, 0);
+
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+if (sljit_get_register_index (TMP3) < 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), SLJIT_MEM1(STACK_TOP), -(3 * sizeof(sljit_sw)));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
+ }
+else
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+ OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(3 * sizeof(sljit_sw)));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 3 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0);
+ GET_LOCAL_BASE(TMP1, 0, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP3, 0);
+ }
+JUMPTO(SLJIT_JUMP, mainloop);
+
+JUMPHERE(jump);
+jump = CMP(SLJIT_NOT_ZERO /* SIG_LESS */, TMP2, 0, SLJIT_IMM, 0);
+/* End of reverting values. */
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+
+JUMPHERE(jump);
+OP1(SLJIT_NEG, TMP2, 0, TMP2, 0);
+OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, TMP1, 0);
+if (sljit_get_register_index (TMP3) < 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
+ }
+else
+ {
+ OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(STACK_TOP), -(2 * sizeof(sljit_sw)));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP3, 0);
+ }
+JUMPTO(SLJIT_JUMP, mainloop);
+}
+
+static void check_wordboundary(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *skipread;
+jump_list *skipread_list = NULL;
+#if PCRE2_CODE_UNIT_WIDTH != 8 || defined SUPPORT_UNICODE
+struct sljit_jump *jump;
+#endif
+
+SLJIT_COMPILE_ASSERT(ctype_word == 0x10, ctype_word_must_be_16);
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+/* Get type of the previous char, and put it to LOCALS1. */
+OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, SLJIT_IMM, 0);
+skipread = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP1, 0);
+skip_char_back(common);
+check_start_used_ptr(common);
+read_char(common);
+
+/* Testing char type. */
+#ifdef SUPPORT_UNICODE
+if (common->use_ucp)
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
+ jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
+ add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0);
+ }
+else
+#endif
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#elif defined SUPPORT_UNICODE
+ /* Here LOCALS1 has already been zeroed. */
+ jump = NULL;
+ if (common->utf)
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), common->ctypes);
+ OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 4 /* ctype_word */);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP1, 0);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ JUMPHERE(jump);
+#elif defined SUPPORT_UNICODE
+ if (jump != NULL)
+ JUMPHERE(jump);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ }
+JUMPHERE(skipread);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+check_str_end(common, &skipread_list);
+peek_char(common, READ_CHAR_MAX);
+
+/* Testing char type. This is a code duplication. */
+#ifdef SUPPORT_UNICODE
+if (common->use_ucp)
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 1);
+ jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_UNDERSCORE);
+ add_jump(compiler, &common->getucd, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ucp_Nd - ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ JUMPHERE(jump);
+ }
+else
+#endif
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ /* TMP2 may be destroyed by peek_char. */
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#elif defined SUPPORT_UNICODE
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+ jump = NULL;
+ if (common->utf)
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+#endif
+ OP1(SLJIT_MOV_U8, TMP2, 0, SLJIT_MEM1(TMP1), common->ctypes);
+ OP2(SLJIT_LSHR, TMP2, 0, TMP2, 0, SLJIT_IMM, 4 /* ctype_word */);
+ OP2(SLJIT_AND, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ JUMPHERE(jump);
+#elif defined SUPPORT_UNICODE
+ if (jump != NULL)
+ JUMPHERE(jump);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ }
+set_jumps(skipread_list, LABEL());
+
+OP2(SLJIT_XOR | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+}
+
+static BOOL optimize_class_ranges(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+int ranges[MAX_CLASS_RANGE_SIZE];
+sljit_u8 bit, cbit, all;
+int i, byte, length = 0;
+
+bit = bits[0] & 0x1;
+/* All bits will be zero or one (since bit is zero or one). */
+all = -bit;
+
+for (i = 0; i < 256; )
+ {
+ byte = i >> 3;
+ if ((i & 0x7) == 0 && bits[byte] == all)
+ i += 8;
+ else
+ {
+ cbit = (bits[byte] >> (i & 0x7)) & 0x1;
+ if (cbit != bit)
+ {
+ if (length >= MAX_CLASS_RANGE_SIZE)
+ return FALSE;
+ ranges[length] = i;
+ length++;
+ bit = cbit;
+ all = -cbit;
+ }
+ i++;
+ }
+ }
+
+if (((bit == 0) && nclass) || ((bit == 1) && !nclass))
+ {
+ if (length >= MAX_CLASS_RANGE_SIZE)
+ return FALSE;
+ ranges[length] = 256;
+ length++;
+ }
+
+if (length < 0 || length > 4)
+ return FALSE;
+
+bit = bits[0] & 0x1;
+if (invert) bit ^= 0x1;
+
+/* No character is accepted. */
+if (length == 0 && bit == 0)
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+
+switch(length)
+ {
+ case 0:
+ /* When bit != 0, all characters are accepted. */
+ return TRUE;
+
+ case 1:
+ add_jump(compiler, backtracks, CMP(bit == 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+ return TRUE;
+
+ case 2:
+ if (ranges[0] + 1 != ranges[1])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+ add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+ return TRUE;
+
+ case 3:
+ if (bit != 0)
+ {
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2]));
+ if (ranges[0] + 1 != ranges[1])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+ return TRUE;
+ }
+
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[0]));
+ if (ranges[1] + 1 != ranges[2])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1]);
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1]));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1]));
+ return TRUE;
+
+ case 4:
+ if ((ranges[1] - ranges[0]) == (ranges[3] - ranges[2])
+ && (ranges[0] | (ranges[2] - ranges[0])) == ranges[2]
+ && (ranges[1] & (ranges[2] - ranges[0])) == 0
+ && is_powerof2(ranges[2] - ranges[0]))
+ {
+ SLJIT_ASSERT((ranges[0] & (ranges[2] - ranges[0])) == 0 && (ranges[2] & ranges[3] & (ranges[2] - ranges[0])) != 0);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[0]);
+ if (ranges[2] + 1 != ranges[3])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2]);
+ add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_LESS : SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2]));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(bit != 0 ? SLJIT_EQUAL : SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2]));
+ return TRUE;
+ }
+
+ if (bit != 0)
+ {
+ i = 0;
+ if (ranges[0] + 1 != ranges[1])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+ i = ranges[0];
+ }
+ else
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[0]));
+
+ if (ranges[2] + 1 != ranges[3])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[2] - i);
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[2]));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[2] - i));
+ return TRUE;
+ }
+
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[0]);
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, ranges[3] - ranges[0]));
+ if (ranges[1] + 1 != ranges[2])
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]);
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, ranges[2] - ranges[1]));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, ranges[1] - ranges[0]));
+ return TRUE;
+
+ default:
+ SLJIT_UNREACHABLE();
+ return FALSE;
+ }
+}
+
+static BOOL optimize_class_chars(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+{
+/* May destroy TMP1. */
+DEFINE_COMPILER;
+uint16_t char_list[MAX_CLASS_CHARS_SIZE];
+uint8_t byte;
+sljit_s32 type;
+int i, j, k, len, c;
+
+if (!sljit_has_cpu_feature(SLJIT_HAS_CMOV))
+ return FALSE;
+
+if (invert)
+ nclass = !nclass;
+
+len = 0;
+
+for (i = 0; i < 32; i++)
+ {
+ byte = bits[i];
+
+ if (nclass)
+ byte = ~byte;
+
+ j = 0;
+ while (byte != 0)
+ {
+ if (byte & 0x1)
+ {
+ c = i * 8 + j;
+
+ k = len;
+
+ if ((c & 0x20) != 0)
+ {
+ for (k = 0; k < len; k++)
+ if (char_list[k] == c - 0x20)
+ {
+ char_list[k] |= 0x120;
+ break;
+ }
+ }
+
+ if (k == len)
+ {
+ if (len >= MAX_CLASS_CHARS_SIZE)
+ return FALSE;
+
+ char_list[len++] = (uint16_t) c;
+ }
+ }
+
+ byte >>= 1;
+ j++;
+ }
+ }
+
+if (len == 0) return FALSE; /* Should never occur, but stops analyzers complaining. */
+
+i = 0;
+j = 0;
+
+if (char_list[0] == 0)
+ {
+ i++;
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_ZERO);
+ }
+else
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, 0);
+
+while (i < len)
+ {
+ if ((char_list[i] & 0x100) != 0)
+ j++;
+ else
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_list[i]);
+ CMOV(SLJIT_ZERO, TMP2, TMP1, 0);
+ }
+ i++;
+ }
+
+if (j != 0)
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x20);
+
+ for (i = 0; i < len; i++)
+ if ((char_list[i] & 0x100) != 0)
+ {
+ j--;
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, char_list[i] & 0xff);
+ CMOV(SLJIT_ZERO, TMP2, TMP1, 0);
+ }
+ }
+
+type = nclass ? SLJIT_NOT_EQUAL : SLJIT_EQUAL;
+add_jump(compiler, backtracks, CMP(type, TMP2, 0, SLJIT_IMM, 0));
+return TRUE;
+}
+
+static BOOL optimize_class(compiler_common *common, const sljit_u8 *bits, BOOL nclass, BOOL invert, jump_list **backtracks)
+{
+/* May destroy TMP1. */
+if (optimize_class_ranges(common, bits, nclass, invert, backtracks))
+ return TRUE;
+return optimize_class_chars(common, bits, nclass, invert, backtracks);
+}
+
+static void check_anynewline(compiler_common *common)
+{
+/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
+DEFINE_COMPILER;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
+OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+#endif
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ }
+#endif
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+static void check_hspace(compiler_common *common)
+{
+/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
+DEFINE_COMPILER;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x09);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x20);
+OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xa0);
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+#endif
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x1680);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x2000);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x200A - 0x2000);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x202f - 0x2000);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x205f - 0x2000);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x3000 - 0x2000);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ }
+#endif
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+static void check_vspace(compiler_common *common)
+{
+/* Check whether TMP1 contains a newline character. TMP2 destroyed. */
+DEFINE_COMPILER;
+
+sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+
+OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x0a);
+OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x0d - 0x0a);
+OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x0a);
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utf)
+ {
+#endif
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, 0x1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2029 - 0x0a);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ }
+#endif
+#endif /* SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == [16|32] */
+OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+
+sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
+}
+
+static void do_casefulcmp(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *label;
+int char1_reg;
+int char2_reg;
+
+if (sljit_get_register_index(TMP3) < 0)
+ {
+ char1_reg = STR_END;
+ char2_reg = STACK_TOP;
+ }
+else
+ {
+ char1_reg = TMP3;
+ char2_reg = RETURN_ADDR;
+ }
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+if (char1_reg == STR_END)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, char1_reg, 0);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, char2_reg, 0);
+ }
+
+if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ {
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ }
+else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+else
+ {
+ label = LABEL();
+ OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0);
+ OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ }
+
+if (char1_reg == STR_END)
+ {
+ OP1(SLJIT_MOV, char1_reg, 0, TMP3, 0);
+ OP1(SLJIT_MOV, char2_reg, 0, RETURN_ADDR, 0);
+ }
+
+sljit_emit_fast_return(compiler, TMP1, 0);
+}
+
+static void do_caselesscmp(compiler_common *common)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+struct sljit_label *label;
+int char1_reg = STR_END;
+int char2_reg;
+int lcc_table;
+int opt_type = 0;
+
+if (sljit_get_register_index(TMP3) < 0)
+ {
+ char2_reg = STACK_TOP;
+ lcc_table = STACK_LIMIT;
+ }
+else
+ {
+ char2_reg = RETURN_ADDR;
+ lcc_table = TMP3;
+ }
+
+if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ opt_type = 1;
+else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ opt_type = 2;
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0);
+
+if (char2_reg == STACK_TOP)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, char2_reg, 0);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, lcc_table, 0);
+ }
+
+OP1(SLJIT_MOV, lcc_table, 0, SLJIT_IMM, common->lcc);
+
+if (opt_type == 1)
+ {
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ }
+else if (opt_type == 2)
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ }
+else
+ {
+ label = LABEL();
+ OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0);
+ OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+jump = CMP(SLJIT_GREATER, char1_reg, 0, SLJIT_IMM, 255);
+#endif
+OP1(SLJIT_MOV_U8, char1_reg, 0, SLJIT_MEM2(lcc_table, char1_reg), 0);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+JUMPHERE(jump);
+jump = CMP(SLJIT_GREATER, char2_reg, 0, SLJIT_IMM, 255);
+#endif
+OP1(SLJIT_MOV_U8, char2_reg, 0, SLJIT_MEM2(lcc_table, char2_reg), 0);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+JUMPHERE(jump);
+#endif
+
+if (opt_type == 0)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+JUMPTO(SLJIT_NOT_ZERO, label);
+
+JUMPHERE(jump);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+if (opt_type == 2)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+if (char2_reg == STACK_TOP)
+ {
+ OP1(SLJIT_MOV, char2_reg, 0, TMP3, 0);
+ OP1(SLJIT_MOV, lcc_table, 0, RETURN_ADDR, 0);
+ }
+
+OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+sljit_emit_fast_return(compiler, TMP1, 0);
+}
+
+#if defined SUPPORT_UNICODE
+
+static PCRE2_SPTR SLJIT_FUNC do_utf_caselesscmp(PCRE2_SPTR src1, PCRE2_SPTR src2, PCRE2_SPTR end1, PCRE2_SPTR end2)
+{
+/* This function would be ineffective to do in JIT level. */
+sljit_u32 c1, c2;
+const ucd_record *ur;
+const sljit_u32 *pp;
+
+while (src1 < end1)
+ {
+ if (src2 >= end2)
+ return (PCRE2_SPTR)1;
+ GETCHARINC(c1, src1);
+ GETCHARINC(c2, src2);
+ ur = GET_UCD(c2);
+ if (c1 != c2 && c1 != c2 + ur->other_case)
+ {
+ pp = PRIV(ucd_caseless_sets) + ur->caseset;
+ for (;;)
+ {
+ if (c1 < *pp) return NULL;
+ if (c1 == *pp++) break;
+ }
+ }
+ }
+return src2;
+}
+
+#endif /* SUPPORT_UNICODE */
+
+static PCRE2_SPTR byte_sequence_compare(compiler_common *common, BOOL caseless, PCRE2_SPTR cc,
+ compare_context *context, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+unsigned int othercasebit = 0;
+PCRE2_SPTR othercasechar = NULL;
+#ifdef SUPPORT_UNICODE
+int utflength;
+#endif
+
+if (caseless && char_has_othercase(common, cc))
+ {
+ othercasebit = char_get_othercase_bit(common, cc);
+ SLJIT_ASSERT(othercasebit);
+ /* Extracting bit difference info. */
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ othercasechar = cc + (othercasebit >> 8);
+ othercasebit &= 0xff;
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ /* Note that this code only handles characters in the BMP. If there
+ ever are characters outside the BMP whose othercase differs in only one
+ bit from itself (there currently are none), this code will need to be
+ revised for PCRE2_CODE_UNIT_WIDTH == 32. */
+ othercasechar = cc + (othercasebit >> 9);
+ if ((othercasebit & 0x100) != 0)
+ othercasebit = (othercasebit & 0xff) << 8;
+ else
+ othercasebit &= 0xff;
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+ }
+
+if (context->sourcereg == -1)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+ if (context->length >= 4)
+ OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ else if (context->length >= 2)
+ OP1(SLJIT_MOV_U16, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ else
+#endif
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+ if (context->length >= 4)
+ OP1(SLJIT_MOV_S32, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ else
+#endif
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#elif PCRE2_CODE_UNIT_WIDTH == 32
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16|32] */
+ context->sourcereg = TMP2;
+ }
+
+#ifdef SUPPORT_UNICODE
+utflength = 1;
+if (common->utf && HAS_EXTRALEN(*cc))
+ utflength += GET_EXTRALEN(*cc);
+
+do
+ {
+#endif
+
+ context->length -= IN_UCHARS(1);
+#if (defined SLJIT_UNALIGNED && SLJIT_UNALIGNED) && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
+
+ /* Unaligned read is supported. */
+ if (othercasebit != 0 && othercasechar == cc)
+ {
+ context->c.asuchars[context->ucharptr] = *cc | othercasebit;
+ context->oc.asuchars[context->ucharptr] = othercasebit;
+ }
+ else
+ {
+ context->c.asuchars[context->ucharptr] = *cc;
+ context->oc.asuchars[context->ucharptr] = 0;
+ }
+ context->ucharptr++;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (context->ucharptr >= 4 || context->length == 0 || (context->ucharptr == 2 && context->length == 1))
+#else
+ if (context->ucharptr >= 2 || context->length == 0)
+#endif
+ {
+ if (context->length >= 4)
+ OP1(SLJIT_MOV_S32, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+ else if (context->length >= 2)
+ OP1(SLJIT_MOV_U16, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ else if (context->length >= 1)
+ OP1(SLJIT_MOV_U8, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
+
+ switch(context->ucharptr)
+ {
+ case 4 / sizeof(PCRE2_UCHAR):
+ if (context->oc.asint != 0)
+ OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asint);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asint | context->oc.asint));
+ break;
+
+ case 2 / sizeof(PCRE2_UCHAR):
+ if (context->oc.asushort != 0)
+ OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asushort);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asushort | context->oc.asushort));
+ break;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ case 1:
+ if (context->oc.asbyte != 0)
+ OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, context->oc.asbyte);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, context->c.asbyte | context->oc.asbyte));
+ break;
+#endif
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ context->ucharptr = 0;
+ }
+
+#else
+
+ /* Unaligned read is unsupported or in 32 bit mode. */
+ if (context->length >= 1)
+ OP1(MOV_UCHAR, context->sourcereg, 0, SLJIT_MEM1(STR_PTR), -context->length);
+
+ context->sourcereg = context->sourcereg == TMP1 ? TMP2 : TMP1;
+
+ if (othercasebit != 0 && othercasechar == cc)
+ {
+ OP2(SLJIT_OR, context->sourcereg, 0, context->sourcereg, 0, SLJIT_IMM, othercasebit);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc | othercasebit));
+ }
+ else
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, context->sourcereg, 0, SLJIT_IMM, *cc));
+
+#endif
+
+ cc++;
+#ifdef SUPPORT_UNICODE
+ utflength--;
+ }
+while (utflength > 0);
+#endif
+
+return cc;
+}
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+
+#define SET_TYPE_OFFSET(value) \
+ if ((value) != typeoffset) \
+ { \
+ if ((value) < typeoffset) \
+ OP2(SLJIT_ADD, typereg, 0, typereg, 0, SLJIT_IMM, typeoffset - (value)); \
+ else \
+ OP2(SLJIT_SUB, typereg, 0, typereg, 0, SLJIT_IMM, (value) - typeoffset); \
+ } \
+ typeoffset = (value);
+
+#define SET_CHAR_OFFSET(value) \
+ if ((value) != charoffset) \
+ { \
+ if ((value) < charoffset) \
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(charoffset - (value))); \
+ else \
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)((value) - charoffset)); \
+ } \
+ charoffset = (value);
+
+static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr);
+
+static void compile_xclass_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+jump_list *found = NULL;
+jump_list **list = (cc[0] & XCL_NOT) == 0 ? &found : backtracks;
+sljit_uw c, charoffset, max = 256, min = READ_CHAR_MAX;
+struct sljit_jump *jump = NULL;
+PCRE2_SPTR ccbegin;
+int compares, invertcmp, numberofcmps;
+#if defined SUPPORT_UNICODE && (PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16)
+BOOL utf = common->utf;
+#endif
+
+#ifdef SUPPORT_UNICODE
+BOOL needstype = FALSE, needsscript = FALSE, needschar = FALSE;
+BOOL charsaved = FALSE;
+int typereg = TMP1;
+const sljit_u32 *other_cases;
+sljit_uw typeoffset;
+#endif
+
+/* Scanning the necessary info. */
+cc++;
+ccbegin = cc;
+compares = 0;
+
+if (cc[-1] & XCL_MAP)
+ {
+ min = 0;
+ cc += 32 / sizeof(PCRE2_UCHAR);
+ }
+
+while (*cc != XCL_END)
+ {
+ compares++;
+ if (*cc == XCL_SINGLE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ if (c > max) max = c;
+ if (c < min) min = c;
+#ifdef SUPPORT_UNICODE
+ needschar = TRUE;
+#endif
+ }
+ else if (*cc == XCL_RANGE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ if (c < min) min = c;
+ GETCHARINCTEST(c, cc);
+ if (c > max) max = c;
+#ifdef SUPPORT_UNICODE
+ needschar = TRUE;
+#endif
+ }
+#ifdef SUPPORT_UNICODE
+ else
+ {
+ SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+ cc++;
+ if (*cc == PT_CLIST)
+ {
+ other_cases = PRIV(ucd_caseless_sets) + cc[1];
+ while (*other_cases != NOTACHAR)
+ {
+ if (*other_cases > max) max = *other_cases;
+ if (*other_cases < min) min = *other_cases;
+ other_cases++;
+ }
+ }
+ else
+ {
+ max = READ_CHAR_MAX;
+ min = 0;
+ }
+
+ switch(*cc)
+ {
+ case PT_ANY:
+ /* Any either accepts everything or ignored. */
+ if (cc[-1] == XCL_PROP)
+ {
+ compile_char1_matchingpath(common, OP_ALLANY, cc, backtracks, FALSE);
+ if (list == backtracks)
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ return;
+ }
+ break;
+
+ case PT_LAMP:
+ case PT_GC:
+ case PT_PC:
+ case PT_ALNUM:
+ needstype = TRUE;
+ break;
+
+ case PT_SC:
+ needsscript = TRUE;
+ break;
+
+ case PT_SPACE:
+ case PT_PXSPACE:
+ case PT_WORD:
+ case PT_PXGRAPH:
+ case PT_PXPRINT:
+ case PT_PXPUNCT:
+ needstype = TRUE;
+ needschar = TRUE;
+ break;
+
+ case PT_CLIST:
+ case PT_UCNC:
+ needschar = TRUE;
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ cc += 2;
+ }
+#endif
+ }
+SLJIT_ASSERT(compares > 0);
+
+/* We are not necessary in utf mode even in 8 bit mode. */
+cc = ccbegin;
+read_char_range(common, min, max, (cc[-1] & XCL_NOT) != 0);
+
+if ((cc[-1] & XCL_HASPROP) == 0)
+ {
+ if ((cc[-1] & XCL_MAP) != 0)
+ {
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+ if (!optimize_class(common, (const sljit_u8 *)cc, (((const sljit_u8 *)cc)[31] & 0x80) != 0, TRUE, &found))
+ {
+ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+ OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ add_jump(compiler, &found, JUMP(SLJIT_NOT_ZERO));
+ }
+
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(jump);
+
+ cc += 32 / sizeof(PCRE2_UCHAR);
+ }
+ else
+ {
+ OP2(SLJIT_SUB, TMP2, 0, TMP1, 0, SLJIT_IMM, min);
+ add_jump(compiler, (cc[-1] & XCL_NOT) == 0 ? backtracks : &found, CMP(SLJIT_GREATER, TMP2, 0, SLJIT_IMM, max - min));
+ }
+ }
+else if ((cc[-1] & XCL_MAP) != 0)
+ {
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+#ifdef SUPPORT_UNICODE
+ charsaved = TRUE;
+#endif
+ if (!optimize_class(common, (const sljit_u8 *)cc, FALSE, TRUE, list))
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ jump = NULL;
+ if (common->utf)
+#endif
+ jump = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+
+ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+ OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ add_jump(compiler, list, JUMP(SLJIT_NOT_ZERO));
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf)
+#endif
+ JUMPHERE(jump);
+ }
+
+ OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+ cc += 32 / sizeof(PCRE2_UCHAR);
+ }
+
+#ifdef SUPPORT_UNICODE
+if (needstype || needsscript)
+ {
+ if (needschar && !charsaved)
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, TMP1, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+ if (!common->utf)
+ {
+ jump = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, MAX_UTF_CODE_POINT + 1);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, INVALID_UTF_CHAR);
+ JUMPHERE(jump);
+ }
+#endif
+
+ OP2(SLJIT_LSHR, TMP2, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+ OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_stage1));
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, UCD_BLOCK_MASK);
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, UCD_BLOCK_SHIFT);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, TMP2, 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_stage2));
+ OP1(SLJIT_MOV_U16, TMP2, 0, SLJIT_MEM2(TMP2, TMP1), 1);
+
+ /* Before anything else, we deal with scripts. */
+ if (needsscript)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, script));
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
+
+ ccbegin = cc;
+
+ while (*cc != XCL_END)
+ {
+ if (*cc == XCL_SINGLE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ }
+ else if (*cc == XCL_RANGE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ GETCHARINCTEST(c, cc);
+ }
+ else
+ {
+ SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+ cc++;
+ if (*cc == PT_SC)
+ {
+ compares--;
+ invertcmp = (compares == 0 && list != backtracks);
+ if (cc[-1] == XCL_NOTPROP)
+ invertcmp ^= 0x1;
+ jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (int)cc[1]);
+ add_jump(compiler, compares > 0 ? list : backtracks, jump);
+ }
+ cc += 2;
+ }
+ }
+
+ cc = ccbegin;
+ }
+
+ if (needschar)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, RETURN_ADDR, 0);
+ }
+
+ if (needstype)
+ {
+ if (!needschar)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM2(TMP1, TMP2), 3);
+ }
+ else
+ {
+ OP2(SLJIT_SHL, TMP2, 0, TMP2, 0, SLJIT_IMM, 3);
+ OP1(SLJIT_MOV_U8, RETURN_ADDR, 0, SLJIT_MEM1(TMP2), (sljit_sw)PRIV(ucd_records) + SLJIT_OFFSETOF(ucd_record, chartype));
+ typereg = RETURN_ADDR;
+ }
+ }
+ }
+#endif
+
+/* Generating code. */
+charoffset = 0;
+numberofcmps = 0;
+#ifdef SUPPORT_UNICODE
+typeoffset = 0;
+#endif
+
+while (*cc != XCL_END)
+ {
+ compares--;
+ invertcmp = (compares == 0 && list != backtracks);
+ jump = NULL;
+
+ if (*cc == XCL_SINGLE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+
+ if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ numberofcmps++;
+ }
+ else if (numberofcmps > 0)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ numberofcmps = 0;
+ }
+ else
+ {
+ jump = CMP(SLJIT_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ numberofcmps = 0;
+ }
+ }
+ else if (*cc == XCL_RANGE)
+ {
+ cc ++;
+ GETCHARINCTEST(c, cc);
+ SET_CHAR_OFFSET(c);
+ GETCHARINCTEST(c, cc);
+
+ if (numberofcmps < 3 && (*cc == XCL_SINGLE || *cc == XCL_RANGE))
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(numberofcmps == 0 ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ numberofcmps++;
+ }
+ else if (numberofcmps > 0)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ numberofcmps = 0;
+ }
+ else
+ {
+ jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, TMP1, 0, SLJIT_IMM, (sljit_sw)(c - charoffset));
+ numberofcmps = 0;
+ }
+ }
+#ifdef SUPPORT_UNICODE
+ else
+ {
+ SLJIT_ASSERT(*cc == XCL_PROP || *cc == XCL_NOTPROP);
+ if (*cc == XCL_NOTPROP)
+ invertcmp ^= 0x1;
+ cc++;
+ switch(*cc)
+ {
+ case PT_ANY:
+ if (!invertcmp)
+ jump = JUMP(SLJIT_JUMP);
+ break;
+
+ case PT_LAMP:
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - typeoffset);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ll - typeoffset);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lt - typeoffset);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ case PT_GC:
+ c = PRIV(ucp_typerange)[(int)cc[1] * 2];
+ SET_TYPE_OFFSET(c);
+ jump = CMP(SLJIT_LESS_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, PRIV(ucp_typerange)[(int)cc[1] * 2 + 1] - c);
+ break;
+
+ case PT_PC:
+ jump = CMP(SLJIT_EQUAL ^ invertcmp, typereg, 0, SLJIT_IMM, (int)cc[1] - typeoffset);
+ break;
+
+ case PT_SC:
+ compares++;
+ /* Do nothing. */
+ break;
+
+ case PT_SPACE:
+ case PT_PXSPACE:
+ SET_CHAR_OFFSET(9);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd - 0x9);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x85 - 0x9);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x9);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ SET_TYPE_OFFSET(ucp_Zl);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Zl);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ case PT_WORD:
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_UNDERSCORE - charoffset));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ /* Fall through. */
+
+ case PT_ALNUM:
+ SET_TYPE_OFFSET(ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Lu - ucp_Ll);
+ OP_FLAGS((*cc == PT_ALNUM) ? SLJIT_MOV : SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ SET_TYPE_OFFSET(ucp_Nd);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_No - ucp_Nd);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ case PT_CLIST:
+ other_cases = PRIV(ucd_caseless_sets) + cc[1];
+
+ /* At least three characters are required.
+ Otherwise this case would be handled by the normal code path. */
+ SLJIT_ASSERT(other_cases[0] != NOTACHAR && other_cases[1] != NOTACHAR && other_cases[2] != NOTACHAR);
+ SLJIT_ASSERT(other_cases[0] < other_cases[1] && other_cases[1] < other_cases[2]);
+
+ /* Optimizing character pairs, if their difference is power of 2. */
+ if (is_powerof2(other_cases[1] ^ other_cases[0]))
+ {
+ if (charoffset == 0)
+ OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
+ else
+ {
+ OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset);
+ OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
+ }
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[1]);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ other_cases += 2;
+ }
+ else if (is_powerof2(other_cases[2] ^ other_cases[1]))
+ {
+ if (charoffset == 0)
+ OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, other_cases[2] ^ other_cases[1]);
+ else
+ {
+ OP2(SLJIT_ADD, TMP2, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)charoffset);
+ OP2(SLJIT_OR, TMP2, 0, TMP2, 0, SLJIT_IMM, other_cases[1] ^ other_cases[0]);
+ }
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, other_cases[2]);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(other_cases[0] - charoffset));
+ OP_FLAGS(SLJIT_OR | ((other_cases[3] == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL);
+
+ other_cases += 3;
+ }
+ else
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ }
+
+ while (*other_cases != NOTACHAR)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(*other_cases++ - charoffset));
+ OP_FLAGS(SLJIT_OR | ((*other_cases == NOTACHAR) ? SLJIT_SET_Z : 0), TMP2, 0, SLJIT_EQUAL);
+ }
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ case PT_UCNC:
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_DOLLAR_SIGN - charoffset));
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_COMMERCIAL_AT - charoffset));
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(CHAR_GRAVE_ACCENT - charoffset));
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ SET_CHAR_OFFSET(0xa0);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (sljit_sw)(0xd7ff - charoffset));
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_LESS_EQUAL);
+ SET_CHAR_OFFSET(0);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xe000 - 0);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_GREATER_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ case PT_PXGRAPH:
+ /* C and Z groups are the farthest two groups. */
+ SET_TYPE_OFFSET(ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
+
+ jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
+
+ /* In case of ucp_Cf, we overwrite the result. */
+ SET_CHAR_OFFSET(0x2066);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x180e - 0x2066);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ JUMPHERE(jump);
+ jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
+ break;
+
+ case PT_PXPRINT:
+ /* C and Z groups are the farthest two groups. */
+ SET_TYPE_OFFSET(ucp_Ll);
+ OP2(SLJIT_SUB | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Ll);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_GREATER);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Zs - ucp_Ll);
+ OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_NOT_EQUAL);
+
+ jump = CMP(SLJIT_NOT_EQUAL, typereg, 0, SLJIT_IMM, ucp_Cf - ucp_Ll);
+
+ /* In case of ucp_Cf, we overwrite the result. */
+ SET_CHAR_OFFSET(0x2066);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x2069 - 0x2066);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x061c - 0x2066);
+ OP_FLAGS(SLJIT_OR, TMP2, 0, SLJIT_EQUAL);
+
+ JUMPHERE(jump);
+ jump = CMP(SLJIT_ZERO ^ invertcmp, TMP2, 0, SLJIT_IMM, 0);
+ break;
+
+ case PT_PXPUNCT:
+ SET_TYPE_OFFSET(ucp_Sc);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_So - ucp_Sc);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_CHAR_OFFSET(0);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0x7f);
+ OP_FLAGS(SLJIT_AND, TMP2, 0, SLJIT_LESS_EQUAL);
+
+ SET_TYPE_OFFSET(ucp_Pc);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS_EQUAL, SLJIT_UNUSED, 0, typereg, 0, SLJIT_IMM, ucp_Ps - ucp_Pc);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_LESS_EQUAL);
+ jump = JUMP(SLJIT_NOT_ZERO ^ invertcmp);
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ cc += 2;
+ }
+#endif
+
+ if (jump != NULL)
+ add_jump(compiler, compares > 0 ? list : backtracks, jump);
+ }
+
+if (found != NULL)
+ set_jumps(found, LABEL());
+}
+
+#undef SET_TYPE_OFFSET
+#undef SET_CHAR_OFFSET
+
+#endif
+
+static PCRE2_SPTR compile_simple_assertion_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks)
+{
+DEFINE_COMPILER;
+int length;
+struct sljit_jump *jump[4];
+#ifdef SUPPORT_UNICODE
+struct sljit_label *label;
+#endif /* SUPPORT_UNICODE */
+
+switch(type)
+ {
+ case OP_SOD:
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
+ return cc;
+
+ case OP_SOM:
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, TMP1, 0));
+ return cc;
+
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ add_jump(compiler, &common->wordboundary, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(type == OP_NOT_WORD_BOUNDARY ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ return cc;
+
+ case OP_EODN:
+ /* Requires rather complex checks. */
+ jump[0] = CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0);
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
+ else
+ {
+ jump[1] = CMP(SLJIT_EQUAL, TMP2, 0, STR_END, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_LESS, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
+ OP_FLAGS(SLJIT_MOV, TMP2, 0, SLJIT_LESS);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
+ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_NOT_EQUAL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL));
+ check_partial(common, TRUE);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(jump[1]);
+ }
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+ }
+ else if (common->nltype == NLTYPE_FIXED)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_END, 0));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline));
+ }
+ else
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_GREATER, SLJIT_UNUSED, 0, TMP2, 0, STR_END, 0);
+ jump[2] = JUMP(SLJIT_GREATER);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_EQUAL) /* LESS */);
+ /* Equal. */
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ jump[3] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+
+ JUMPHERE(jump[1]);
+ if (common->nltype == NLTYPE_ANYCRLF)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, STR_END, 0));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL));
+ }
+ else
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0);
+ read_char_range(common, common->nlmin, common->nlmax, TRUE);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+ add_jump(compiler, &common->anynewline, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+ }
+ JUMPHERE(jump[2]);
+ JUMPHERE(jump[3]);
+ }
+ JUMPHERE(jump[0]);
+ check_partial(common, FALSE);
+ return cc;
+
+ case OP_EOD:
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ check_partial(common, FALSE);
+ return cc;
+
+ case OP_DOLL:
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+
+ if (!common->endonly)
+ compile_simple_assertion_matchingpath(common, OP_EODN, cc, backtracks);
+ else
+ {
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0));
+ check_partial(common, FALSE);
+ }
+ return cc;
+
+ case OP_DOLLM:
+ jump[1] = CMP(SLJIT_LESS, STR_PTR, 0, STR_END, 0);
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTEOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ check_partial(common, FALSE);
+ jump[0] = JUMP(SLJIT_JUMP);
+ JUMPHERE(jump[1]);
+
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0));
+ else
+ {
+ jump[1] = CMP(SLJIT_LESS_EQUAL, TMP2, 0, STR_END, 0);
+ /* STR_PTR = STR_END - IN_UCHARS(1) */
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ check_partial(common, TRUE);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(jump[1]);
+ }
+
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+ }
+ else
+ {
+ peek_char(common, common->nlmax);
+ check_newlinechar(common, common->nltype, backtracks, FALSE);
+ }
+ JUMPHERE(jump[0]);
+ return cc;
+
+ case OP_CIRC:
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0));
+ OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ return cc;
+
+ case OP_CIRCM:
+ OP1(SLJIT_MOV, TMP2, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, begin));
+ jump[1] = CMP(SLJIT_GREATER, STR_PTR, 0, TMP1, 0);
+ OP2(SLJIT_AND32 | SLJIT_SET_Z, SLJIT_UNUSED, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(jit_arguments, options), SLJIT_IMM, PCRE2_NOTBOL);
+ add_jump(compiler, backtracks, JUMP(SLJIT_NOT_ZERO32));
+ jump[0] = JUMP(SLJIT_JUMP);
+ JUMPHERE(jump[1]);
+
+ if (!common->alt_circumflex)
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ OP2(SLJIT_SUB, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(2));
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, TMP2, 0, TMP1, 0));
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-2));
+ OP1(MOV_UCHAR, TMP2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, common->newline & 0xff));
+ }
+ else
+ {
+ skip_char_back(common);
+ read_char_range(common, common->nlmin, common->nlmax, TRUE);
+ check_newlinechar(common, common->nltype, backtracks, FALSE);
+ }
+ JUMPHERE(jump[0]);
+ return cc;
+
+ case OP_REVERSE:
+ length = GET(cc, 0);
+ if (length == 0)
+ return cc + LINK_SIZE;
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+#ifdef SUPPORT_UNICODE
+ if (common->utf)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, length);
+ label = LABEL();
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP3, 0));
+ skip_char_back(common);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+#endif
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, begin));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS, STR_PTR, 0, TMP1, 0));
+ }
+ check_start_used_ptr(common);
+ return cc + LINK_SIZE;
+ }
+SLJIT_UNREACHABLE();
+return cc;
+}
+
+#ifdef SUPPORT_UNICODE
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+
+static PCRE2_SPTR SLJIT_FUNC do_extuni_utf(jit_arguments *args, PCRE2_SPTR cc)
+{
+PCRE2_SPTR start_subject = args->begin;
+PCRE2_SPTR end_subject = args->end;
+int lgb, rgb, len, ricount;
+PCRE2_SPTR prevcc, bptr;
+uint32_t c;
+
+prevcc = cc;
+GETCHARINC(c, cc);
+lgb = UCD_GRAPHBREAK(c);
+
+while (cc < end_subject)
+ {
+ len = 1;
+ GETCHARLEN(c, cc, len);
+ rgb = UCD_GRAPHBREAK(c);
+
+ if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+
+ /* Not breaking between Regional Indicators is allowed only if there
+ are an even number of preceding RIs. */
+
+ if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+ {
+ ricount = 0;
+ bptr = prevcc;
+
+ /* bptr is pointing to the left-hand character */
+ while (bptr > start_subject)
+ {
+ bptr--;
+ BACKCHAR(bptr);
+ GETCHAR(c, bptr);
+
+ if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break;
+
+ ricount++;
+ }
+
+ if ((ricount & 1) != 0) break; /* Grapheme break required */
+ }
+
+ /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+ allows any number of them before a following Extended_Pictographic. */
+
+ if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+ lgb != ucp_gbExtended_Pictographic)
+ lgb = rgb;
+
+ prevcc = cc;
+ cc += len;
+ }
+
+return cc;
+}
+
+#endif
+
+static PCRE2_SPTR SLJIT_FUNC do_extuni_no_utf(jit_arguments *args, PCRE2_SPTR cc)
+{
+PCRE2_SPTR start_subject = args->begin;
+PCRE2_SPTR end_subject = args->end;
+int lgb, rgb, ricount;
+PCRE2_SPTR bptr;
+uint32_t c;
+
+GETCHARINC(c, cc);
+lgb = UCD_GRAPHBREAK(c);
+
+while (cc < end_subject)
+ {
+ c = *cc;
+ rgb = UCD_GRAPHBREAK(c);
+
+ if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+
+ /* Not breaking between Regional Indicators is allowed only if there
+ are an even number of preceding RIs. */
+
+ if (lgb == ucp_gbRegionalIndicator && rgb == ucp_gbRegionalIndicator)
+ {
+ ricount = 0;
+ bptr = cc - 1;
+
+ /* bptr is pointing to the left-hand character */
+ while (bptr > start_subject)
+ {
+ bptr--;
+ c = *bptr;
+
+ if (UCD_GRAPHBREAK(c) != ucp_gbRegionalIndicator) break;
+
+ ricount++;
+ }
+
+ if ((ricount & 1) != 0) break; /* Grapheme break required */
+ }
+
+ /* If Extend or ZWJ follows Extended_Pictographic, do not update lgb; this
+ allows any number of them before a following Extended_Pictographic. */
+
+ if ((rgb != ucp_gbExtend && rgb != ucp_gbZWJ) ||
+ lgb != ucp_gbExtended_Pictographic)
+ lgb = rgb;
+
+ cc++;
+ }
+
+return cc;
+}
+
+#endif
+
+static PCRE2_SPTR compile_char1_matchingpath(compiler_common *common, PCRE2_UCHAR type, PCRE2_SPTR cc, jump_list **backtracks, BOOL check_str_ptr)
+{
+DEFINE_COMPILER;
+int length;
+unsigned int c, oc, bit;
+compare_context context;
+struct sljit_jump *jump[3];
+jump_list *end_list;
+#ifdef SUPPORT_UNICODE
+PCRE2_UCHAR propdata[5];
+#endif /* SUPPORT_UNICODE */
+
+switch(type)
+ {
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ /* Digits are usually 0-9, so it is worth to optimize them. */
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_digit, FALSE))
+ read_char7_type(common, type == OP_NOT_DIGIT);
+ else
+#endif
+ read_char8_type(common, type == OP_NOT_DIGIT);
+ /* Flip the starting bit in the negative case. */
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_digit);
+ add_jump(compiler, backtracks, JUMP(type == OP_DIGIT ? SLJIT_ZERO : SLJIT_NOT_ZERO));
+ return cc;
+
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_space, FALSE))
+ read_char7_type(common, type == OP_NOT_WHITESPACE);
+ else
+#endif
+ read_char8_type(common, type == OP_NOT_WHITESPACE);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_space);
+ add_jump(compiler, backtracks, JUMP(type == OP_WHITESPACE ? SLJIT_ZERO : SLJIT_NOT_ZERO));
+ return cc;
+
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (common->utf && is_char7_bitset((const sljit_u8*)common->ctypes - cbit_length + cbit_word, FALSE))
+ read_char7_type(common, type == OP_NOT_WORDCHAR);
+ else
+#endif
+ read_char8_type(common, type == OP_NOT_WORDCHAR);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, ctype_word);
+ add_jump(compiler, backtracks, JUMP(type == OP_WORDCHAR ? SLJIT_ZERO : SLJIT_NOT_ZERO));
+ return cc;
+
+ case OP_ANY:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char_range(common, common->nlmin, common->nlmax, TRUE);
+ if (common->nltype == NLTYPE_FIXED && common->newline > 255)
+ {
+ jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, (common->newline >> 8) & 0xff);
+ end_list = NULL;
+ if (common->mode != PCRE2_JIT_PARTIAL_HARD)
+ add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ else
+ check_str_end(common, &end_list);
+
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, common->newline & 0xff));
+ set_jumps(end_list, LABEL());
+ JUMPHERE(jump[0]);
+ }
+ else
+ check_newlinechar(common, common->nltype, backtracks, TRUE);
+ return cc;
+
+ case OP_ALLANY:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf)
+ {
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+#if PCRE2_CODE_UNIT_WIDTH == 8 || PCRE2_CODE_UNIT_WIDTH == 16
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP2(SLJIT_AND, TMP1, 0, TMP1, 0, SLJIT_IMM, 0xfc00);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, SLJIT_IMM, 0xd800);
+ OP_FLAGS(SLJIT_MOV, TMP1, 0, SLJIT_EQUAL);
+ OP2(SLJIT_SHL, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+#endif
+ JUMPHERE(jump[0]);
+#endif /* PCRE2_CODE_UNIT_WIDTH == [8|16] */
+ return cc;
+ }
+#endif
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ return cc;
+
+ case OP_ANYBYTE:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ return cc;
+
+#ifdef SUPPORT_UNICODE
+ case OP_NOTPROP:
+ case OP_PROP:
+ propdata[0] = XCL_HASPROP;
+ propdata[1] = type == OP_NOTPROP ? XCL_NOTPROP : XCL_PROP;
+ propdata[2] = cc[0];
+ propdata[3] = cc[1];
+ propdata[4] = XCL_END;
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ compile_xclass_matchingpath(common, propdata, backtracks);
+ return cc + 2;
+#endif
+
+ case OP_ANYNL:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char_range(common, common->bsr_nlmin, common->bsr_nlmax, FALSE);
+ jump[0] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_CR);
+ /* We don't need to handle soft partial matching case. */
+ end_list = NULL;
+ if (common->mode != PCRE2_JIT_PARTIAL_HARD)
+ add_jump(compiler, &end_list, CMP(SLJIT_GREATER_EQUAL, STR_PTR, 0, STR_END, 0));
+ else
+ check_str_end(common, &end_list);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ jump[1] = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, CHAR_NL);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ jump[2] = JUMP(SLJIT_JUMP);
+ JUMPHERE(jump[0]);
+ check_newlinechar(common, common->bsr_nltype, backtracks, FALSE);
+ set_jumps(end_list, LABEL());
+ JUMPHERE(jump[1]);
+ JUMPHERE(jump[2]);
+ return cc;
+
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char_range(common, 0x9, 0x3000, type == OP_NOT_HSPACE);
+ add_jump(compiler, &common->hspace, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(type == OP_NOT_HSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ return cc;
+
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ read_char_range(common, 0xa, 0x2029, type == OP_NOT_VSPACE);
+ add_jump(compiler, &common->vspace, JUMP(SLJIT_FAST_CALL));
+ sljit_set_current_flags(compiler, SLJIT_SET_Z);
+ add_jump(compiler, backtracks, JUMP(type == OP_NOT_VSPACE ? SLJIT_NOT_ZERO : SLJIT_ZERO));
+ return cc;
+
+#ifdef SUPPORT_UNICODE
+ case OP_EXTUNI:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+
+ SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+ OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM,
+ common->utf ? SLJIT_FUNC_OFFSET(do_extuni_utf) : SLJIT_FUNC_OFFSET(do_extuni_no_utf));
+#else
+ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_extuni_no_utf));
+#endif
+
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+
+ if (common->mode == PCRE2_JIT_PARTIAL_HARD)
+ {
+ jump[0] = CMP(SLJIT_LESS, SLJIT_RETURN_REG, 0, STR_END, 0);
+ /* Since we successfully read a char above, partial matching must occure. */
+ check_partial(common, TRUE);
+ JUMPHERE(jump[0]);
+ }
+ return cc;
+#endif
+
+ case OP_CHAR:
+ case OP_CHARI:
+ length = 1;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(*cc)) length += GET_EXTRALEN(*cc);
+#endif
+ if (common->mode == PCRE2_JIT_COMPLETE && check_str_ptr
+ && (type == OP_CHAR || !char_has_othercase(common, cc) || char_get_othercase_bit(common, cc) != 0))
+ {
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(length));
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
+
+ context.length = IN_UCHARS(length);
+ context.sourcereg = -1;
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+ context.ucharptr = 0;
+#endif
+ return byte_sequence_compare(common, type == OP_CHARI, cc, &context, backtracks);
+ }
+
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+#ifdef SUPPORT_UNICODE
+ if (common->utf)
+ {
+ GETCHAR(c, cc);
+ }
+ else
+#endif
+ c = *cc;
+
+ if (type == OP_CHAR || !char_has_othercase(common, cc))
+ {
+ read_char_range(common, c, c, FALSE);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+ return cc + length;
+ }
+ oc = char_othercase(common, c);
+ read_char_range(common, c < oc ? c : oc, c > oc ? c : oc, FALSE);
+ bit = c ^ oc;
+ if (is_powerof2(bit))
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit));
+ return cc + length;
+ }
+ jump[0] = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c);
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, oc));
+ JUMPHERE(jump[0]);
+ return cc + length;
+
+ case OP_NOT:
+ case OP_NOTI:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+
+ length = 1;
+#ifdef SUPPORT_UNICODE
+ if (common->utf)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ c = *cc;
+ if (c < 128)
+ {
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(STR_PTR), 0);
+ if (type == OP_NOT || !char_has_othercase(common, cc))
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+ else
+ {
+ /* Since UTF8 code page is fixed, we know that c is in [a-z] or [A-Z] range. */
+ OP2(SLJIT_OR, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x20);
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, c | 0x20));
+ }
+ /* Skip the variable-length character. */
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ jump[0] = CMP(SLJIT_LESS, TMP1, 0, SLJIT_IMM, 0xc0);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)PRIV(utf8_table4) - 0xc0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP1, 0);
+ JUMPHERE(jump[0]);
+ return cc + 1;
+ }
+ else
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ {
+ GETCHARLEN(c, cc, length);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ c = *cc;
+
+ if (type == OP_NOT || !char_has_othercase(common, cc))
+ {
+ read_char_range(common, c, c, TRUE);
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+ }
+ else
+ {
+ oc = char_othercase(common, c);
+ read_char_range(common, c < oc ? c : oc, c > oc ? c : oc, TRUE);
+ bit = c ^ oc;
+ if (is_powerof2(bit))
+ {
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, bit);
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c | bit));
+ }
+ else
+ {
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, c));
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, oc));
+ }
+ }
+ return cc + length;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ bit = (common->utf && is_char7_bitset((const sljit_u8 *)cc, type == OP_NCLASS)) ? 127 : 255;
+ read_char_range(common, 0, bit, type == OP_NCLASS);
+#else
+ read_char_range(common, 0, 255, type == OP_NCLASS);
+#endif
+
+ if (optimize_class(common, (const sljit_u8 *)cc, type == OP_NCLASS, FALSE, backtracks))
+ return cc + 32 / sizeof(PCRE2_UCHAR);
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ jump[0] = NULL;
+ if (common->utf)
+ {
+ jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, bit);
+ if (type == OP_CLASS)
+ {
+ add_jump(compiler, backtracks, jump[0]);
+ jump[0] = NULL;
+ }
+ }
+#elif PCRE2_CODE_UNIT_WIDTH != 8
+ jump[0] = CMP(SLJIT_GREATER, TMP1, 0, SLJIT_IMM, 255);
+ if (type == OP_CLASS)
+ {
+ add_jump(compiler, backtracks, jump[0]);
+ jump[0] = NULL;
+ }
+#endif /* SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8 */
+
+ OP2(SLJIT_AND, TMP2, 0, TMP1, 0, SLJIT_IMM, 0x7);
+ OP2(SLJIT_LSHR, TMP1, 0, TMP1, 0, SLJIT_IMM, 3);
+ OP1(SLJIT_MOV_U8, TMP1, 0, SLJIT_MEM1(TMP1), (sljit_sw)cc);
+ OP2(SLJIT_SHL, TMP2, 0, SLJIT_IMM, 1, TMP2, 0);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP1, 0, TMP2, 0);
+ add_jump(compiler, backtracks, JUMP(SLJIT_ZERO));
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ if (jump[0] != NULL)
+ JUMPHERE(jump[0]);
+#endif
+ return cc + 32 / sizeof(PCRE2_UCHAR);
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ case OP_XCLASS:
+ if (check_str_ptr)
+ detect_partial_match(common, backtracks);
+ compile_xclass_matchingpath(common, cc + LINK_SIZE, backtracks);
+ return cc + GET(cc, 0) - 1;
+#endif
+ }
+SLJIT_UNREACHABLE();
+return cc;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_charn_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, jump_list **backtracks)
+{
+/* This function consumes at least one input character. */
+/* To decrease the number of length checks, we try to concatenate the fixed length character sequences. */
+DEFINE_COMPILER;
+PCRE2_SPTR ccbegin = cc;
+compare_context context;
+int size;
+
+context.length = 0;
+do
+ {
+ if (cc >= ccend)
+ break;
+
+ if (*cc == OP_CHAR)
+ {
+ size = 1;
+#ifdef SUPPORT_UNICODE
+ if (common->utf && HAS_EXTRALEN(cc[1]))
+ size += GET_EXTRALEN(cc[1]);
+#endif
+ }
+ else if (*cc == OP_CHARI)
+ {
+ size = 1;
+#ifdef SUPPORT_UNICODE
+ if (common->utf)
+ {
+ if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
+ size = 0;
+ else if (HAS_EXTRALEN(cc[1]))
+ size += GET_EXTRALEN(cc[1]);
+ }
+ else
+#endif
+ if (char_has_othercase(common, cc + 1) && char_get_othercase_bit(common, cc + 1) == 0)
+ size = 0;
+ }
+ else
+ size = 0;
+
+ cc += 1 + size;
+ context.length += IN_UCHARS(size);
+ }
+while (size > 0 && context.length <= 128);
+
+cc = ccbegin;
+if (context.length > 0)
+ {
+ /* We have a fixed-length byte sequence. */
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, context.length);
+ add_jump(compiler, backtracks, CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0));
+
+ context.sourcereg = -1;
+#if defined SLJIT_UNALIGNED && SLJIT_UNALIGNED
+ context.ucharptr = 0;
+#endif
+ do cc = byte_sequence_compare(common, *cc == OP_CHARI, cc + 1, &context, backtracks); while (context.length > 0);
+ return cc;
+ }
+
+/* A non-fixed length character will be checked if length == 0. */
+return compile_char1_matchingpath(common, *cc, cc + 1, backtracks, TRUE);
+}
+
+/* Forward definitions. */
+static void compile_matchingpath(compiler_common *, PCRE2_SPTR, PCRE2_SPTR, backtrack_common *);
+static void compile_backtrackingpath(compiler_common *, struct backtrack_common *);
+
+#define PUSH_BACKTRACK(size, ccstart, error) \
+ do \
+ { \
+ backtrack = sljit_alloc_memory(compiler, (size)); \
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
+ return error; \
+ memset(backtrack, 0, size); \
+ backtrack->prev = parent->top; \
+ backtrack->cc = (ccstart); \
+ parent->top = backtrack; \
+ } \
+ while (0)
+
+#define PUSH_BACKTRACK_NOVALUE(size, ccstart) \
+ do \
+ { \
+ backtrack = sljit_alloc_memory(compiler, (size)); \
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
+ return; \
+ memset(backtrack, 0, size); \
+ backtrack->prev = parent->top; \
+ backtrack->cc = (ccstart); \
+ parent->top = backtrack; \
+ } \
+ while (0)
+
+#define BACKTRACK_AS(type) ((type *)backtrack)
+
+static void compile_dnref_search(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks)
+{
+/* The OVECTOR offset goes to TMP2. */
+DEFINE_COMPILER;
+int count = GET2(cc, 1 + IMM2_SIZE);
+PCRE2_SPTR slot = common->name_table + GET2(cc, 1) * common->name_entry_size;
+unsigned int offset;
+jump_list *found = NULL;
+
+SLJIT_ASSERT(*cc == OP_DNREF || *cc == OP_DNREFI);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+
+count--;
+while (count-- > 0)
+ {
+ offset = GET2(slot, 0) << 1;
+ GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset));
+ add_jump(compiler, &found, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0));
+ slot += common->name_entry_size;
+ }
+
+offset = GET2(slot, 0) << 1;
+GET_LOCAL_BASE(TMP2, 0, OVECTOR(offset));
+if (backtracks != NULL && !common->unset_backref)
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0));
+
+set_jumps(found, LABEL());
+}
+
+static void compile_ref_matchingpath(compiler_common *common, PCRE2_SPTR cc, jump_list **backtracks, BOOL withchecks, BOOL emptyfail)
+{
+DEFINE_COMPILER;
+BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
+int offset = 0;
+struct sljit_jump *jump = NULL;
+struct sljit_jump *partial;
+struct sljit_jump *nopartial;
+
+if (ref)
+ {
+ offset = GET2(cc, 1) << 1;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+ /* OVECTOR(1) contains the "string begin - 1" constant. */
+ if (withchecks && !common->unset_backref)
+ add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+ }
+else
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+
+#if defined SUPPORT_UNICODE
+if (common->utf && *cc == OP_REFI)
+ {
+ SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+ if (ref)
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ else
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+
+ if (withchecks)
+ jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_R2, 0);
+ /* No free saved registers so save data on stack. */
+
+ OP1(SLJIT_MOV, SLJIT_R3, 0, STR_END, 0);
+ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+
+ if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1));
+ else
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_LESS, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
+
+ add_jump(compiler, backtracks, JUMP(SLJIT_LESS));
+
+ nopartial = JUMP(SLJIT_NOT_EQUAL);
+ OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
+ check_partial(common, FALSE);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(nopartial);
+ }
+ }
+else
+#endif /* SUPPORT_UNICODE */
+ {
+ if (ref)
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
+ else
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0);
+
+ if (withchecks)
+ jump = JUMP(SLJIT_ZERO);
+
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
+ partial = CMP(SLJIT_GREATER, STR_PTR, 0, STR_END, 0);
+ if (common->mode == PCRE2_JIT_COMPLETE)
+ add_jump(compiler, backtracks, partial);
+
+ add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+
+ if (common->mode != PCRE2_JIT_COMPLETE)
+ {
+ nopartial = JUMP(SLJIT_JUMP);
+ JUMPHERE(partial);
+ /* TMP2 -= STR_END - STR_PTR */
+ OP2(SLJIT_SUB, TMP2, 0, TMP2, 0, STR_PTR, 0);
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, STR_END, 0);
+ partial = CMP(SLJIT_EQUAL, TMP2, 0, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
+ add_jump(compiler, *cc == OP_REF ? &common->casefulcmp : &common->caselesscmp, JUMP(SLJIT_FAST_CALL));
+ add_jump(compiler, backtracks, CMP(SLJIT_NOT_EQUAL, TMP2, 0, SLJIT_IMM, 0));
+ JUMPHERE(partial);
+ check_partial(common, FALSE);
+ add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
+ JUMPHERE(nopartial);
+ }
+ }
+
+if (jump != NULL)
+ {
+ if (emptyfail)
+ add_jump(compiler, backtracks, jump);
+ else
+ JUMPHERE(jump);
+ }
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_ref_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
+backtrack_common *backtrack;
+PCRE2_UCHAR type;
+int offset = 0;
+struct sljit_label *label;
+struct sljit_jump *zerolength;
+struct sljit_jump *jump = NULL;
+PCRE2_SPTR ccbegin = cc;
+int min = 0, max = 0;
+BOOL minimize;
+
+PUSH_BACKTRACK(sizeof(ref_iterator_backtrack), cc, NULL);
+
+if (ref)
+ offset = GET2(cc, 1) << 1;
+else
+ cc += IMM2_SIZE;
+type = cc[1 + IMM2_SIZE];
+
+SLJIT_COMPILE_ASSERT((OP_CRSTAR & 0x1) == 0, crstar_opcode_must_be_even);
+minimize = (type & 0x1) != 0;
+switch(type)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ min = 0;
+ max = 0;
+ cc += 1 + IMM2_SIZE + 1;
+ break;
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ min = 1;
+ max = 0;
+ cc += 1 + IMM2_SIZE + 1;
+ break;
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ min = 0;
+ max = 1;
+ cc += 1 + IMM2_SIZE + 1;
+ break;
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ min = GET2(cc, 1 + IMM2_SIZE + 1);
+ max = GET2(cc, 1 + IMM2_SIZE + 1 + IMM2_SIZE);
+ cc += 1 + IMM2_SIZE + 1 + 2 * IMM2_SIZE;
+ break;
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+
+if (!minimize)
+ {
+ if (min == 0)
+ {
+ allocate_stack(common, 2);
+ if (ref)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
+ /* Temporary release of STR_PTR. */
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ /* Handles both invalid and empty cases. Since the minimum repeat,
+ is zero the invalid case is basically the same as an empty case. */
+ if (ref)
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ else
+ {
+ compile_dnref_search(common, ccbegin, NULL);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ }
+ /* Restore if not zero length. */
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ }
+ else
+ {
+ allocate_stack(common, 1);
+ if (ref)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ if (ref)
+ {
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ }
+ else
+ {
+ compile_dnref_search(common, ccbegin, &backtrack->topbacktracks);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, TMP2, 0);
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ }
+ }
+
+ if (min > 1 || max > 1)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, 0);
+
+ label = LABEL();
+ if (!ref)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+ compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, FALSE, FALSE);
+
+ if (min > 1 || max > 1)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
+ if (min > 1)
+ CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, label);
+ if (max > 1)
+ {
+ jump = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, max);
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, label);
+ JUMPHERE(jump);
+ }
+ }
+
+ if (max == 0)
+ {
+ /* Includes min > 1 case as well. */
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, label);
+ }
+
+ JUMPHERE(zerolength);
+ BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
+
+ count_match(common);
+ return cc;
+ }
+
+allocate_stack(common, ref ? 2 : 3);
+if (ref)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+if (type != OP_CRMINSTAR)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
+
+if (min == 0)
+ {
+ /* Handles both invalid and empty cases. Since the minimum repeat,
+ is zero the invalid case is basically the same as an empty case. */
+ if (ref)
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ else
+ {
+ compile_dnref_search(common, ccbegin, NULL);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0);
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ }
+ /* Length is non-zero, we can match real repeats. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ jump = JUMP(SLJIT_JUMP);
+ }
+else
+ {
+ if (ref)
+ {
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ }
+ else
+ {
+ compile_dnref_search(common, ccbegin, &backtrack->topbacktracks);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0);
+ zerolength = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ }
+ }
+
+BACKTRACK_AS(ref_iterator_backtrack)->matchingpath = LABEL();
+if (max > 0)
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, max));
+
+if (!ref)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+compile_ref_matchingpath(common, ccbegin, &backtrack->topbacktracks, TRUE, TRUE);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+if (min > 1)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+ CMPTO(SLJIT_LESS, TMP1, 0, SLJIT_IMM, min, BACKTRACK_AS(ref_iterator_backtrack)->matchingpath);
+ }
+else if (max > 0)
+ OP2(SLJIT_ADD, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 1);
+
+if (jump != NULL)
+ JUMPHERE(jump);
+JUMPHERE(zerolength);
+
+count_match(common);
+return cc;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_recurse_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+recurse_entry *entry = common->entries;
+recurse_entry *prev = NULL;
+sljit_sw start = GET(cc, 1);
+PCRE2_SPTR start_cc;
+BOOL needs_control_head;
+
+PUSH_BACKTRACK(sizeof(recurse_backtrack), cc, NULL);
+
+/* Inlining simple patterns. */
+if (get_framesize(common, common->start + start, NULL, TRUE, &needs_control_head) == no_stack)
+ {
+ start_cc = common->start + start;
+ compile_matchingpath(common, next_opcode(common, start_cc), bracketend(start_cc) - (1 + LINK_SIZE), backtrack);
+ BACKTRACK_AS(recurse_backtrack)->inlined_pattern = TRUE;
+ return cc + 1 + LINK_SIZE;
+ }
+
+while (entry != NULL)
+ {
+ if (entry->start == start)
+ break;
+ prev = entry;
+ entry = entry->next;
+ }
+
+if (entry == NULL)
+ {
+ entry = sljit_alloc_memory(compiler, sizeof(recurse_entry));
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+ entry->next = NULL;
+ entry->entry_label = NULL;
+ entry->backtrack_label = NULL;
+ entry->entry_calls = NULL;
+ entry->backtrack_calls = NULL;
+ entry->start = start;
+
+ if (prev != NULL)
+ prev->next = entry;
+ else
+ common->entries = entry;
+ }
+
+BACKTRACK_AS(recurse_backtrack)->entry = entry;
+
+if (entry->entry_label == NULL)
+ add_jump(compiler, &entry->entry_calls, JUMP(SLJIT_FAST_CALL));
+else
+ JUMPTO(SLJIT_FAST_CALL, entry->entry_label);
+/* Leave if the match is failed. */
+add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0));
+BACKTRACK_AS(recurse_backtrack)->matchingpath = LABEL();
+return cc + 1 + LINK_SIZE;
+}
+
+static sljit_s32 SLJIT_FUNC do_callout(struct jit_arguments *arguments, pcre2_callout_block *callout_block, PCRE2_SPTR *jit_ovector)
+{
+PCRE2_SPTR begin;
+PCRE2_SIZE *ovector;
+sljit_u32 oveccount, capture_top;
+
+if (arguments->callout == NULL)
+ return 0;
+
+SLJIT_COMPILE_ASSERT(sizeof (PCRE2_SIZE) <= sizeof (sljit_sw), pcre2_size_must_be_lower_than_sljit_sw_size);
+
+begin = arguments->begin;
+ovector = (PCRE2_SIZE*)(callout_block + 1);
+oveccount = callout_block->capture_top;
+
+SLJIT_ASSERT(oveccount >= 1);
+
+callout_block->version = 2;
+callout_block->callout_flags = 0;
+
+/* Offsets in subject. */
+callout_block->subject_length = arguments->end - arguments->begin;
+callout_block->start_match = jit_ovector[0] - begin;
+callout_block->current_position = (PCRE2_SPTR)callout_block->offset_vector - begin;
+callout_block->subject = begin;
+
+/* Convert and copy the JIT offset vector to the ovector array. */
+callout_block->capture_top = 1;
+callout_block->offset_vector = ovector;
+
+ovector[0] = PCRE2_UNSET;
+ovector[1] = PCRE2_UNSET;
+ovector += 2;
+jit_ovector += 2;
+capture_top = 1;
+
+/* Convert pointers to sizes. */
+while (--oveccount != 0)
+ {
+ capture_top++;
+
+ ovector[0] = (PCRE2_SIZE)(jit_ovector[0] - begin);
+ ovector[1] = (PCRE2_SIZE)(jit_ovector[1] - begin);
+
+ if (ovector[0] != PCRE2_UNSET)
+ callout_block->capture_top = capture_top;
+
+ ovector += 2;
+ jit_ovector += 2;
+ }
+
+return (arguments->callout)(callout_block, arguments->callout_data);
+}
+
+#define CALLOUT_ARG_OFFSET(arg) \
+ SLJIT_OFFSETOF(pcre2_callout_block, arg)
+
+static SLJIT_INLINE PCRE2_SPTR compile_callout_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+sljit_s32 mov_opcode;
+unsigned int callout_length = (*cc == OP_CALLOUT)
+ ? PRIV(OP_lengths)[OP_CALLOUT] : GET(cc, 1 + 2 * LINK_SIZE);
+sljit_sw value1;
+sljit_sw value2;
+sljit_sw value3;
+sljit_uw callout_arg_size = (common->re->top_bracket + 1) * 2 * sizeof(sljit_sw);
+
+PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
+
+callout_arg_size = (sizeof(pcre2_callout_block) + callout_arg_size + sizeof(sljit_sw) - 1) / sizeof(sljit_sw);
+
+allocate_stack(common, callout_arg_size);
+
+SLJIT_ASSERT(common->capture_last_ptr != 0);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+value1 = (*cc == OP_CALLOUT) ? cc[1 + 2 * LINK_SIZE] : 0;
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_number), SLJIT_IMM, value1);
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_last), TMP2, 0);
+OP1(SLJIT_MOV_U32, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(capture_top), SLJIT_IMM, common->re->top_bracket + 1);
+
+/* These pointer sized fields temporarly stores internal variables. */
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(offset_vector), STR_PTR, 0);
+
+if (common->mark_ptr != 0)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr));
+mov_opcode = (sizeof(PCRE2_SIZE) == 4) ? SLJIT_MOV_U32 : SLJIT_MOV;
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(pattern_position), SLJIT_IMM, GET(cc, 1));
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(next_item_length), SLJIT_IMM, GET(cc, 1 + LINK_SIZE));
+
+if (*cc == OP_CALLOUT)
+ {
+ value1 = 0;
+ value2 = 0;
+ value3 = 0;
+ }
+else
+ {
+ value1 = (sljit_sw) (cc + (1 + 4*LINK_SIZE) + 1);
+ value2 = (callout_length - (1 + 4*LINK_SIZE + 2));
+ value3 = (sljit_sw) (GET(cc, 1 + 3*LINK_SIZE));
+ }
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string), SLJIT_IMM, value1);
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_length), SLJIT_IMM, value2);
+OP1(mov_opcode, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(callout_string_offset), SLJIT_IMM, value3);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), CALLOUT_ARG_OFFSET(mark), (common->mark_ptr != 0) ? TMP2 : SLJIT_IMM, 0);
+
+SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+
+/* Needed to save important temporary registers. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STR_PTR, 0);
+/* SLJIT_R0 = arguments */
+OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0);
+GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START);
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(S32) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout));
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+free_stack(common, callout_arg_size);
+
+/* Check return value. */
+OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER32));
+if (common->abort_label == NULL)
+ add_jump(compiler, &common->abort, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */);
+else
+ JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->abort_label);
+return cc + callout_length;
+}
+
+#undef CALLOUT_ARG_SIZE
+#undef CALLOUT_ARG_OFFSET
+
+static SLJIT_INLINE BOOL assert_needs_str_ptr_saving(PCRE2_SPTR cc)
+{
+while (TRUE)
+ {
+ switch (*cc)
+ {
+ case OP_CALLOUT_STR:
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_CALLOUT:
+ case OP_ALT:
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+
+ case OP_KET:
+ return FALSE;
+
+ default:
+ return TRUE;
+ }
+ }
+}
+
+static PCRE2_SPTR compile_assert_matchingpath(compiler_common *common, PCRE2_SPTR cc, assert_backtrack *backtrack, BOOL conditional)
+{
+DEFINE_COMPILER;
+int framesize;
+int extrasize;
+BOOL local_quit_available = FALSE;
+BOOL needs_control_head;
+int private_data_ptr;
+backtrack_common altbacktrack;
+PCRE2_SPTR ccbegin;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR bra = OP_BRA;
+jump_list *tmp = NULL;
+jump_list **target = (conditional) ? &backtrack->condfailed : &backtrack->common.topbacktracks;
+jump_list **found;
+/* Saving previous accept variables. */
+BOOL save_local_quit_available = common->local_quit_available;
+BOOL save_in_positive_assertion = common->in_positive_assertion;
+then_trap_backtrack *save_then_trap = common->then_trap;
+struct sljit_label *save_quit_label = common->quit_label;
+struct sljit_label *save_accept_label = common->accept_label;
+jump_list *save_quit = common->quit;
+jump_list *save_positive_assertion_quit = common->positive_assertion_quit;
+jump_list *save_accept = common->accept;
+struct sljit_jump *jump;
+struct sljit_jump *brajump = NULL;
+
+/* Assert captures then. */
+common->then_trap = NULL;
+
+if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
+ {
+ SLJIT_ASSERT(!conditional);
+ bra = *cc;
+ cc++;
+ }
+private_data_ptr = PRIVATE_DATA(cc);
+SLJIT_ASSERT(private_data_ptr != 0);
+framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head);
+backtrack->framesize = framesize;
+backtrack->private_data_ptr = private_data_ptr;
+opcode = *cc;
+SLJIT_ASSERT(opcode >= OP_ASSERT && opcode <= OP_ASSERTBACK_NOT);
+found = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK) ? &tmp : target;
+ccbegin = cc;
+cc += GET(cc, 1);
+
+if (bra == OP_BRAMINZERO)
+ {
+ /* This is a braminzero backtrack path. */
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+ }
+
+if (framesize < 0)
+ {
+ extrasize = 1;
+ if (bra == OP_BRA && !assert_needs_str_ptr_saving(ccbegin + 1 + LINK_SIZE))
+ extrasize = 0;
+
+ if (needs_control_head)
+ extrasize++;
+
+ if (framesize == no_frame)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
+
+ if (extrasize > 0)
+ allocate_stack(common, extrasize);
+
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+ if (needs_control_head)
+ {
+ SLJIT_ASSERT(extrasize == 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+ }
+ }
+else
+ {
+ extrasize = needs_control_head ? 3 : 2;
+ allocate_stack(common, framesize + extrasize);
+
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, (framesize + extrasize) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+ if (needs_control_head)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+ }
+ else
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0);
+
+ init_frame(common, ccbegin, NULL, framesize + extrasize - 1, extrasize);
+ }
+
+memset(&altbacktrack, 0, sizeof(backtrack_common));
+if (conditional || (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT))
+ {
+ /* Control verbs cannot escape from these asserts. */
+ local_quit_available = TRUE;
+ common->local_quit_available = TRUE;
+ common->quit_label = NULL;
+ common->quit = NULL;
+ }
+
+common->in_positive_assertion = (opcode == OP_ASSERT || opcode == OP_ASSERTBACK);
+common->positive_assertion_quit = NULL;
+
+while (1)
+ {
+ common->accept_label = NULL;
+ common->accept = NULL;
+ altbacktrack.top = NULL;
+ altbacktrack.topbacktracks = NULL;
+
+ if (*ccbegin == OP_ALT && extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+ altbacktrack.cc = ccbegin;
+ compile_matchingpath(common, ccbegin + 1 + LINK_SIZE, cc, &altbacktrack);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ {
+ if (local_quit_available)
+ {
+ common->local_quit_available = save_local_quit_available;
+ common->quit_label = save_quit_label;
+ common->quit = save_quit;
+ }
+ common->in_positive_assertion = save_in_positive_assertion;
+ common->then_trap = save_then_trap;
+ common->accept_label = save_accept_label;
+ common->positive_assertion_quit = save_positive_assertion_quit;
+ common->accept = save_accept;
+ return NULL;
+ }
+ common->accept_label = LABEL();
+ if (common->accept != NULL)
+ set_jumps(common->accept, common->accept_label);
+
+ /* Reset stack. */
+ if (framesize < 0)
+ {
+ if (framesize == no_frame)
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ else if (extrasize > 0)
+ free_stack(common, extrasize);
+
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
+ }
+ else
+ {
+ if ((opcode != OP_ASSERT_NOT && opcode != OP_ASSERTBACK_NOT) || conditional)
+ {
+ /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
+ }
+ else
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 2));
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
+ }
+ }
+
+ if (opcode == OP_ASSERT_NOT || opcode == OP_ASSERTBACK_NOT)
+ {
+ /* We know that STR_PTR was stored on the top of the stack. */
+ if (conditional)
+ {
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), needs_control_head ? STACK(-2) : STACK(-1));
+ }
+ else if (bra == OP_BRAZERO)
+ {
+ if (framesize < 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize));
+ else
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-framesize - extrasize));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ }
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ else if (framesize >= 0)
+ {
+ /* For OP_BRA and OP_BRAMINZERO. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-framesize - 1));
+ }
+ }
+ add_jump(compiler, found, JUMP(SLJIT_JUMP));
+
+ compile_backtrackingpath(common, altbacktrack.top);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ {
+ if (local_quit_available)
+ {
+ common->local_quit_available = save_local_quit_available;
+ common->quit_label = save_quit_label;
+ common->quit = save_quit;
+ }
+ common->in_positive_assertion = save_in_positive_assertion;
+ common->then_trap = save_then_trap;
+ common->accept_label = save_accept_label;
+ common->positive_assertion_quit = save_positive_assertion_quit;
+ common->accept = save_accept;
+ return NULL;
+ }
+ set_jumps(altbacktrack.topbacktracks, LABEL());
+
+ if (*cc != OP_ALT)
+ break;
+
+ ccbegin = cc;
+ cc += GET(cc, 1);
+ }
+
+if (local_quit_available)
+ {
+ SLJIT_ASSERT(common->positive_assertion_quit == NULL);
+ /* Makes the check less complicated below. */
+ common->positive_assertion_quit = common->quit;
+ }
+
+/* None of them matched. */
+if (common->positive_assertion_quit != NULL)
+ {
+ jump = JUMP(SLJIT_JUMP);
+ set_jumps(common->positive_assertion_quit, LABEL());
+ SLJIT_ASSERT(framesize != no_stack);
+ if (framesize < 0)
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, extrasize * sizeof(sljit_sw));
+ else
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (extrasize + 1) * sizeof(sljit_sw));
+ }
+ JUMPHERE(jump);
+ }
+
+if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(1));
+
+if (opcode == OP_ASSERT || opcode == OP_ASSERTBACK)
+ {
+ /* Assert is failed. */
+ if ((conditional && extrasize > 0) || bra == OP_BRAZERO)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+ if (framesize < 0)
+ {
+ /* The topmost item should be 0. */
+ if (bra == OP_BRAZERO)
+ {
+ if (extrasize == 2)
+ free_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ else if (extrasize > 0)
+ free_stack(common, extrasize);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1));
+ /* The topmost item should be 0. */
+ if (bra == OP_BRAZERO)
+ {
+ free_stack(common, framesize + extrasize - 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ else
+ free_stack(common, framesize + extrasize);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ }
+ jump = JUMP(SLJIT_JUMP);
+ if (bra != OP_BRAZERO)
+ add_jump(compiler, target, jump);
+
+ /* Assert is successful. */
+ set_jumps(tmp, LABEL());
+ if (framesize < 0)
+ {
+ /* We know that STR_PTR was stored on the top of the stack. */
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize));
+
+ /* Keep the STR_PTR on the top of the stack. */
+ if (bra == OP_BRAZERO)
+ {
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ if (extrasize == 2)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ }
+ else if (bra == OP_BRAMINZERO)
+ {
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ }
+ else
+ {
+ if (bra == OP_BRA)
+ {
+ /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(-extrasize + 1));
+ }
+ else
+ {
+ /* We don't need to keep the STR_PTR, only the previous private_data_ptr. */
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + 2) * sizeof(sljit_sw));
+ if (extrasize == 2)
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ if (bra == OP_BRAMINZERO)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), bra == OP_BRAZERO ? STR_PTR : SLJIT_IMM, 0);
+ }
+ }
+ }
+
+ if (bra == OP_BRAZERO)
+ {
+ backtrack->matchingpath = LABEL();
+ SET_LABEL(jump, backtrack->matchingpath);
+ }
+ else if (bra == OP_BRAMINZERO)
+ {
+ JUMPTO(SLJIT_JUMP, backtrack->matchingpath);
+ JUMPHERE(brajump);
+ if (framesize >= 0)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (framesize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ }
+ set_jumps(backtrack->common.topbacktracks, LABEL());
+ }
+ }
+else
+ {
+ /* AssertNot is successful. */
+ if (framesize < 0)
+ {
+ if (extrasize > 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+ if (bra != OP_BRA)
+ {
+ if (extrasize == 2)
+ free_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ else if (extrasize > 0)
+ free_stack(common, extrasize);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(extrasize - 1));
+ /* The topmost item should be 0. */
+ if (bra != OP_BRA)
+ {
+ free_stack(common, framesize + extrasize - 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ else
+ free_stack(common, framesize + extrasize);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ }
+
+ if (bra == OP_BRAZERO)
+ backtrack->matchingpath = LABEL();
+ else if (bra == OP_BRAMINZERO)
+ {
+ JUMPTO(SLJIT_JUMP, backtrack->matchingpath);
+ JUMPHERE(brajump);
+ }
+
+ if (bra != OP_BRA)
+ {
+ SLJIT_ASSERT(found == &backtrack->common.topbacktracks);
+ set_jumps(backtrack->common.topbacktracks, LABEL());
+ backtrack->common.topbacktracks = NULL;
+ }
+ }
+
+if (local_quit_available)
+ {
+ common->local_quit_available = save_local_quit_available;
+ common->quit_label = save_quit_label;
+ common->quit = save_quit;
+ }
+common->in_positive_assertion = save_in_positive_assertion;
+common->then_trap = save_then_trap;
+common->accept_label = save_accept_label;
+common->positive_assertion_quit = save_positive_assertion_quit;
+common->accept = save_accept;
+return cc + 1 + LINK_SIZE;
+}
+
+static SLJIT_INLINE void match_once_common(compiler_common *common, PCRE2_UCHAR ket, int framesize, int private_data_ptr, BOOL has_alternatives, BOOL needs_control_head)
+{
+DEFINE_COMPILER;
+int stacksize;
+
+if (framesize < 0)
+ {
+ if (framesize == no_frame)
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ else
+ {
+ stacksize = needs_control_head ? 1 : 0;
+ if (ket != OP_KET || has_alternatives)
+ stacksize++;
+
+ if (stacksize > 0)
+ free_stack(common, stacksize);
+ }
+
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), (ket != OP_KET || has_alternatives) ? STACK(-2) : STACK(-1));
+
+ /* TMP2 which is set here used by OP_KETRMAX below. */
+ if (ket == OP_KETRMAX)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
+ else if (ket == OP_KETRMIN)
+ {
+ /* Move the STR_PTR to the private_data_ptr. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-1));
+ }
+ }
+else
+ {
+ stacksize = (ket != OP_KET || has_alternatives) ? 2 : 1;
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, (framesize + stacksize) * sizeof(sljit_sw));
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-1));
+
+ if (ket == OP_KETRMAX)
+ {
+ /* TMP2 which is set here used by OP_KETRMAX below. */
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ }
+ }
+if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0);
+}
+
+static SLJIT_INLINE int match_capture_common(compiler_common *common, int stacksize, int offset, int private_data_ptr)
+{
+DEFINE_COMPILER;
+
+if (common->capture_last_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+ stacksize++;
+ }
+if (common->optimized_cbracket[offset >> 1] == 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+ stacksize += 2;
+ }
+return stacksize;
+}
+
+/*
+ Handling bracketed expressions is probably the most complex part.
+
+ Stack layout naming characters:
+ S - Push the current STR_PTR
+ 0 - Push a 0 (NULL)
+ A - Push the current STR_PTR. Needed for restoring the STR_PTR
+ before the next alternative. Not pushed if there are no alternatives.
+ M - Any values pushed by the current alternative. Can be empty, or anything.
+ C - Push the previous OVECTOR(i), OVECTOR(i+1) and OVECTOR_PRIV(i) to the stack.
+ L - Push the previous local (pointed by localptr) to the stack
+ () - opional values stored on the stack
+ ()* - optonal, can be stored multiple times
+
+ The following list shows the regular expression templates, their PCRE byte codes
+ and stack layout supported by pcre-sljit.
+
+ (?:) OP_BRA | OP_KET A M
+ () OP_CBRA | OP_KET C M
+ (?:)+ OP_BRA | OP_KETRMAX 0 A M S ( A M S )*
+ OP_SBRA | OP_KETRMAX 0 L M S ( L M S )*
+ (?:)+? OP_BRA | OP_KETRMIN 0 A M S ( A M S )*
+ OP_SBRA | OP_KETRMIN 0 L M S ( L M S )*
+ ()+ OP_CBRA | OP_KETRMAX 0 C M S ( C M S )*
+ OP_SCBRA | OP_KETRMAX 0 C M S ( C M S )*
+ ()+? OP_CBRA | OP_KETRMIN 0 C M S ( C M S )*
+ OP_SCBRA | OP_KETRMIN 0 C M S ( C M S )*
+ (?:)? OP_BRAZERO | OP_BRA | OP_KET S ( A M 0 )
+ (?:)?? OP_BRAMINZERO | OP_BRA | OP_KET S ( A M 0 )
+ ()? OP_BRAZERO | OP_CBRA | OP_KET S ( C M 0 )
+ ()?? OP_BRAMINZERO | OP_CBRA | OP_KET S ( C M 0 )
+ (?:)* OP_BRAZERO | OP_BRA | OP_KETRMAX S 0 ( A M S )*
+ OP_BRAZERO | OP_SBRA | OP_KETRMAX S 0 ( L M S )*
+ (?:)*? OP_BRAMINZERO | OP_BRA | OP_KETRMIN S 0 ( A M S )*
+ OP_BRAMINZERO | OP_SBRA | OP_KETRMIN S 0 ( L M S )*
+ ()* OP_BRAZERO | OP_CBRA | OP_KETRMAX S 0 ( C M S )*
+ OP_BRAZERO | OP_SCBRA | OP_KETRMAX S 0 ( C M S )*
+ ()*? OP_BRAMINZERO | OP_CBRA | OP_KETRMIN S 0 ( C M S )*
+ OP_BRAMINZERO | OP_SCBRA | OP_KETRMIN S 0 ( C M S )*
+
+
+ Stack layout naming characters:
+ A - Push the alternative index (starting from 0) on the stack.
+ Not pushed if there is no alternatives.
+ M - Any values pushed by the current alternative. Can be empty, or anything.
+
+ The next list shows the possible content of a bracket:
+ (|) OP_*BRA | OP_ALT ... M A
+ (?()|) OP_*COND | OP_ALT M A
+ (?>|) OP_ONCE | OP_ALT ... [stack trace] M A
+ Or nothing, if trace is unnecessary
+*/
+
+static PCRE2_SPTR compile_bracket_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode;
+int private_data_ptr = 0;
+int offset = 0;
+int i, stacksize;
+int repeat_ptr = 0, repeat_length = 0;
+int repeat_type = 0, repeat_count = 0;
+PCRE2_SPTR ccbegin;
+PCRE2_SPTR matchingpath;
+PCRE2_SPTR slot;
+PCRE2_UCHAR bra = OP_BRA;
+PCRE2_UCHAR ket;
+assert_backtrack *assert;
+BOOL has_alternatives;
+BOOL needs_control_head = FALSE;
+struct sljit_jump *jump;
+struct sljit_jump *skip;
+struct sljit_label *rmax_label = NULL;
+struct sljit_jump *braminzero = NULL;
+
+PUSH_BACKTRACK(sizeof(bracket_backtrack), cc, NULL);
+
+if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
+ {
+ bra = *cc;
+ cc++;
+ opcode = *cc;
+ }
+
+opcode = *cc;
+ccbegin = cc;
+matchingpath = bracketend(cc) - 1 - LINK_SIZE;
+ket = *matchingpath;
+if (ket == OP_KET && PRIVATE_DATA(matchingpath) != 0)
+ {
+ repeat_ptr = PRIVATE_DATA(matchingpath);
+ repeat_length = PRIVATE_DATA(matchingpath + 1);
+ repeat_type = PRIVATE_DATA(matchingpath + 2);
+ repeat_count = PRIVATE_DATA(matchingpath + 3);
+ SLJIT_ASSERT(repeat_length != 0 && repeat_type != 0 && repeat_count != 0);
+ if (repeat_type == OP_UPTO)
+ ket = OP_KETRMAX;
+ if (repeat_type == OP_MINUPTO)
+ ket = OP_KETRMIN;
+ }
+
+matchingpath = ccbegin + 1 + LINK_SIZE;
+SLJIT_ASSERT(ket == OP_KET || ket == OP_KETRMAX || ket == OP_KETRMIN);
+SLJIT_ASSERT(!((bra == OP_BRAZERO && ket == OP_KETRMIN) || (bra == OP_BRAMINZERO && ket == OP_KETRMAX)));
+cc += GET(cc, 1);
+
+has_alternatives = *cc == OP_ALT;
+if (SLJIT_UNLIKELY(opcode == OP_COND || opcode == OP_SCOND))
+ {
+ SLJIT_COMPILE_ASSERT(OP_DNRREF == OP_RREF + 1 && OP_FALSE == OP_RREF + 2 && OP_TRUE == OP_RREF + 3,
+ compile_time_checks_must_be_grouped_together);
+ has_alternatives = ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL) ? FALSE : TRUE;
+ }
+
+if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
+ opcode = OP_SCOND;
+
+if (opcode == OP_CBRA || opcode == OP_SCBRA)
+ {
+ /* Capturing brackets has a pre-allocated space. */
+ offset = GET2(ccbegin, 1 + LINK_SIZE);
+ if (common->optimized_cbracket[offset] == 0)
+ {
+ private_data_ptr = OVECTOR_PRIV(offset);
+ offset <<= 1;
+ }
+ else
+ {
+ offset <<= 1;
+ private_data_ptr = OVECTOR(offset);
+ }
+ BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr;
+ matchingpath += IMM2_SIZE;
+ }
+else if (opcode == OP_ONCE || opcode == OP_SBRA || opcode == OP_SCOND)
+ {
+ /* Other brackets simply allocate the next entry. */
+ private_data_ptr = PRIVATE_DATA(ccbegin);
+ SLJIT_ASSERT(private_data_ptr != 0);
+ BACKTRACK_AS(bracket_backtrack)->private_data_ptr = private_data_ptr;
+ if (opcode == OP_ONCE)
+ BACKTRACK_AS(bracket_backtrack)->u.framesize = get_framesize(common, ccbegin, NULL, FALSE, &needs_control_head);
+ }
+
+/* Instructions before the first alternative. */
+stacksize = 0;
+if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO))
+ stacksize++;
+if (bra == OP_BRAZERO)
+ stacksize++;
+
+if (stacksize > 0)
+ allocate_stack(common, stacksize);
+
+stacksize = 0;
+if (ket == OP_KETRMAX || (ket == OP_KETRMIN && bra != OP_BRAMINZERO))
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+ stacksize++;
+ }
+
+if (bra == OP_BRAZERO)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+
+if (bra == OP_BRAMINZERO)
+ {
+ /* This is a backtrack path! (Since the try-path of OP_BRAMINZERO matches to the empty string) */
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ if (ket != OP_KETRMIN)
+ {
+ free_stack(common, 1);
+ braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+ }
+ else
+ {
+ if (opcode == OP_ONCE || opcode >= OP_SBRA)
+ {
+ jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ /* Nothing stored during the first run. */
+ skip = JUMP(SLJIT_JUMP);
+ JUMPHERE(jump);
+ /* Checking zero-length iteration. */
+ if (opcode != OP_ONCE || BACKTRACK_AS(bracket_backtrack)->u.framesize < 0)
+ {
+ /* When we come from outside, private_data_ptr contains the previous STR_PTR. */
+ braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ }
+ else
+ {
+ /* Except when the whole stack frame must be saved. */
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ braminzero = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-BACKTRACK_AS(bracket_backtrack)->u.framesize - 2));
+ }
+ JUMPHERE(skip);
+ }
+ else
+ {
+ jump = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ JUMPHERE(jump);
+ }
+ }
+ }
+
+if (repeat_type != 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, repeat_count);
+ if (repeat_type == OP_EXACT)
+ rmax_label = LABEL();
+ }
+
+if (ket == OP_KETRMIN)
+ BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL();
+
+if (ket == OP_KETRMAX)
+ {
+ rmax_label = LABEL();
+ if (has_alternatives && opcode != OP_ONCE && opcode < OP_SBRA && repeat_type == 0)
+ BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = rmax_label;
+ }
+
+/* Handling capturing brackets and alternatives. */
+if (opcode == OP_ONCE)
+ {
+ stacksize = 0;
+ if (needs_control_head)
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ stacksize++;
+ }
+
+ if (BACKTRACK_AS(bracket_backtrack)->u.framesize < 0)
+ {
+ /* Neither capturing brackets nor recursions are found in the block. */
+ if (ket == OP_KETRMIN)
+ {
+ stacksize += 2;
+ if (!needs_control_head)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ }
+ else
+ {
+ if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
+ if (ket == OP_KETRMAX || has_alternatives)
+ stacksize++;
+ }
+
+ if (stacksize > 0)
+ allocate_stack(common, stacksize);
+
+ stacksize = 0;
+ if (needs_control_head)
+ {
+ stacksize++;
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+ }
+
+ if (ket == OP_KETRMIN)
+ {
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+ if (BACKTRACK_AS(bracket_backtrack)->u.framesize == no_frame)
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, needs_control_head ? (2 * sizeof(sljit_sw)) : sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize + 1), TMP2, 0);
+ }
+ else if (ket == OP_KETRMAX || has_alternatives)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+ }
+ else
+ {
+ if (ket != OP_KET || has_alternatives)
+ stacksize++;
+
+ stacksize += BACKTRACK_AS(bracket_backtrack)->u.framesize + 1;
+ allocate_stack(common, stacksize);
+
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP2(SLJIT_ADD, TMP2, 0, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+
+ stacksize = needs_control_head ? 1 : 0;
+ if (ket != OP_KET || has_alternatives)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
+ stacksize++;
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP1, 0);
+ }
+ init_frame(common, ccbegin, NULL, BACKTRACK_AS(bracket_backtrack)->u.framesize + stacksize, stacksize + 1);
+ }
+ }
+else if (opcode == OP_CBRA || opcode == OP_SCBRA)
+ {
+ /* Saving the previous values. */
+ if (common->optimized_cbracket[offset >> 1] != 0)
+ {
+ SLJIT_ASSERT(private_data_ptr == OVECTOR(offset));
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+ }
+ }
+else if (opcode == OP_SBRA || opcode == OP_SCOND)
+ {
+ /* Saving the previous value. */
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+ }
+else if (has_alternatives)
+ {
+ /* Pushing the starting string pointer. */
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ }
+
+/* Generating code for the first alternative. */
+if (opcode == OP_COND || opcode == OP_SCOND)
+ {
+ if (*matchingpath == OP_CREF)
+ {
+ SLJIT_ASSERT(has_alternatives);
+ add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed),
+ CMP(SLJIT_EQUAL, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(matchingpath, 1) << 1), SLJIT_MEM1(SLJIT_SP), OVECTOR(1)));
+ matchingpath += 1 + IMM2_SIZE;
+ }
+ else if (*matchingpath == OP_DNCREF)
+ {
+ SLJIT_ASSERT(has_alternatives);
+
+ i = GET2(matchingpath, 1 + IMM2_SIZE);
+ slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size;
+ OP1(SLJIT_MOV, TMP3, 0, STR_PTR, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
+ slot += common->name_entry_size;
+ i--;
+ while (i-- > 0)
+ {
+ OP2(SLJIT_SUB, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(GET2(slot, 0) << 1), TMP1, 0);
+ OP2(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, TMP2, 0, STR_PTR, 0);
+ slot += common->name_entry_size;
+ }
+ OP1(SLJIT_MOV, STR_PTR, 0, TMP3, 0);
+ add_jump(compiler, &(BACKTRACK_AS(bracket_backtrack)->u.condfailed), JUMP(SLJIT_ZERO));
+ matchingpath += 1 + 2 * IMM2_SIZE;
+ }
+ else if ((*matchingpath >= OP_RREF && *matchingpath <= OP_TRUE) || *matchingpath == OP_FAIL)
+ {
+ /* Never has other case. */
+ BACKTRACK_AS(bracket_backtrack)->u.condfailed = NULL;
+ SLJIT_ASSERT(!has_alternatives);
+
+ if (*matchingpath == OP_TRUE)
+ {
+ stacksize = 1;
+ matchingpath++;
+ }
+ else if (*matchingpath == OP_FALSE || *matchingpath == OP_FAIL)
+ stacksize = 0;
+ else if (*matchingpath == OP_RREF)
+ {
+ stacksize = GET2(matchingpath, 1);
+ if (common->currententry == NULL)
+ stacksize = 0;
+ else if (stacksize == RREF_ANY)
+ stacksize = 1;
+ else if (common->currententry->start == 0)
+ stacksize = stacksize == 0;
+ else
+ stacksize = stacksize == (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE);
+
+ if (stacksize != 0)
+ matchingpath += 1 + IMM2_SIZE;
+ }
+ else
+ {
+ if (common->currententry == NULL || common->currententry->start == 0)
+ stacksize = 0;
+ else
+ {
+ stacksize = GET2(matchingpath, 1 + IMM2_SIZE);
+ slot = common->name_table + GET2(matchingpath, 1) * common->name_entry_size;
+ i = (int)GET2(common->start, common->currententry->start + 1 + LINK_SIZE);
+ while (stacksize > 0)
+ {
+ if ((int)GET2(slot, 0) == i)
+ break;
+ slot += common->name_entry_size;
+ stacksize--;
+ }
+ }
+
+ if (stacksize != 0)
+ matchingpath += 1 + 2 * IMM2_SIZE;
+ }
+
+ /* The stacksize == 0 is a common "else" case. */
+ if (stacksize == 0)
+ {
+ if (*cc == OP_ALT)
+ {
+ matchingpath = cc + 1 + LINK_SIZE;
+ cc += GET(cc, 1);
+ }
+ else
+ matchingpath = cc;
+ }
+ }
+ else
+ {
+ SLJIT_ASSERT(has_alternatives && *matchingpath >= OP_ASSERT && *matchingpath <= OP_ASSERTBACK_NOT);
+ /* Similar code as PUSH_BACKTRACK macro. */
+ assert = sljit_alloc_memory(compiler, sizeof(assert_backtrack));
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+ memset(assert, 0, sizeof(assert_backtrack));
+ assert->common.cc = matchingpath;
+ BACKTRACK_AS(bracket_backtrack)->u.assert = assert;
+ matchingpath = compile_assert_matchingpath(common, matchingpath, assert, TRUE);
+ }
+ }
+
+compile_matchingpath(common, matchingpath, cc, backtrack);
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+
+if (opcode == OP_ONCE)
+ match_once_common(common, ket, BACKTRACK_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head);
+
+stacksize = 0;
+if (repeat_type == OP_MINUPTO)
+ {
+ /* We need to preserve the counter. TMP2 will be used below. */
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr);
+ stacksize++;
+ }
+if (ket != OP_KET || bra != OP_BRA)
+ stacksize++;
+if (offset != 0)
+ {
+ if (common->capture_last_ptr != 0)
+ stacksize++;
+ if (common->optimized_cbracket[offset >> 1] == 0)
+ stacksize += 2;
+ }
+if (has_alternatives && opcode != OP_ONCE)
+ stacksize++;
+
+if (stacksize > 0)
+ allocate_stack(common, stacksize);
+
+stacksize = 0;
+if (repeat_type == OP_MINUPTO)
+ {
+ /* TMP2 was set above. */
+ OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1);
+ stacksize++;
+ }
+
+if (ket != OP_KET || bra != OP_BRA)
+ {
+ if (ket != OP_KET)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+ else
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+ stacksize++;
+ }
+
+if (offset != 0)
+ stacksize = match_capture_common(common, stacksize, offset, private_data_ptr);
+
+if (has_alternatives)
+ {
+ if (opcode != OP_ONCE)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+ if (ket != OP_KETRMAX)
+ BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
+ }
+
+/* Must be after the matchingpath label. */
+if (offset != 0 && common->optimized_cbracket[offset >> 1] != 0)
+ {
+ SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+ }
+
+if (ket == OP_KETRMAX)
+ {
+ if (repeat_type != 0)
+ {
+ if (has_alternatives)
+ BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, rmax_label);
+ /* Drop STR_PTR for greedy plus quantifier. */
+ if (opcode != OP_ONCE)
+ free_stack(common, 1);
+ }
+ else if (opcode == OP_ONCE || opcode >= OP_SBRA)
+ {
+ if (has_alternatives)
+ BACKTRACK_AS(bracket_backtrack)->alternative_matchingpath = LABEL();
+ /* Checking zero-length iteration. */
+ if (opcode != OP_ONCE)
+ {
+ CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STR_PTR, 0, rmax_label);
+ /* Drop STR_PTR for greedy plus quantifier. */
+ if (bra != OP_BRAZERO)
+ free_stack(common, 1);
+ }
+ else
+ /* TMP2 must contain the starting STR_PTR. */
+ CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, rmax_label);
+ }
+ else
+ JUMPTO(SLJIT_JUMP, rmax_label);
+ BACKTRACK_AS(bracket_backtrack)->recursive_matchingpath = LABEL();
+ }
+
+if (repeat_type == OP_EXACT)
+ {
+ count_match(common);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, rmax_label);
+ }
+else if (repeat_type == OP_UPTO)
+ {
+ /* We need to preserve the counter. */
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr);
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+ }
+
+if (bra == OP_BRAZERO)
+ BACKTRACK_AS(bracket_backtrack)->zero_matchingpath = LABEL();
+
+if (bra == OP_BRAMINZERO)
+ {
+ /* This is a backtrack path! (From the viewpoint of OP_BRAMINZERO) */
+ JUMPTO(SLJIT_JUMP, ((braminzero_backtrack *)parent)->matchingpath);
+ if (braminzero != NULL)
+ {
+ JUMPHERE(braminzero);
+ /* We need to release the end pointer to perform the
+ backtrack for the zero-length iteration. When
+ framesize is < 0, OP_ONCE will do the release itself. */
+ if (opcode == OP_ONCE && BACKTRACK_AS(bracket_backtrack)->u.framesize >= 0)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (BACKTRACK_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw));
+ }
+ else if (ket == OP_KETRMIN && opcode != OP_ONCE)
+ free_stack(common, 1);
+ }
+ /* Continue to the normal backtrack. */
+ }
+
+if ((ket != OP_KET && bra != OP_BRAMINZERO) || bra == OP_BRAZERO)
+ count_match(common);
+
+/* Skip the other alternatives. */
+while (*cc == OP_ALT)
+ cc += GET(cc, 1);
+cc += 1 + LINK_SIZE;
+
+if (opcode == OP_ONCE)
+ {
+ /* We temporarily encode the needs_control_head in the lowest bit.
+ Note: on the target architectures of SLJIT the ((x << 1) >> 1) returns
+ the same value for small signed numbers (including negative numbers). */
+ BACKTRACK_AS(bracket_backtrack)->u.framesize = (BACKTRACK_AS(bracket_backtrack)->u.framesize << 1) | (needs_control_head ? 1 : 0);
+ }
+return cc + repeat_length;
+}
+
+static PCRE2_SPTR compile_bracketpos_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode;
+int private_data_ptr;
+int cbraprivptr = 0;
+BOOL needs_control_head;
+int framesize;
+int stacksize;
+int offset = 0;
+BOOL zero = FALSE;
+PCRE2_SPTR ccbegin = NULL;
+int stack; /* Also contains the offset of control head. */
+struct sljit_label *loop = NULL;
+struct jump_list *emptymatch = NULL;
+
+PUSH_BACKTRACK(sizeof(bracketpos_backtrack), cc, NULL);
+if (*cc == OP_BRAPOSZERO)
+ {
+ zero = TRUE;
+ cc++;
+ }
+
+opcode = *cc;
+private_data_ptr = PRIVATE_DATA(cc);
+SLJIT_ASSERT(private_data_ptr != 0);
+BACKTRACK_AS(bracketpos_backtrack)->private_data_ptr = private_data_ptr;
+switch(opcode)
+ {
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ ccbegin = cc + 1 + LINK_SIZE;
+ break;
+
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ offset = GET2(cc, 1 + LINK_SIZE);
+ /* This case cannot be optimized in the same was as
+ normal capturing brackets. */
+ SLJIT_ASSERT(common->optimized_cbracket[offset] == 0);
+ cbraprivptr = OVECTOR_PRIV(offset);
+ offset <<= 1;
+ ccbegin = cc + 1 + LINK_SIZE + IMM2_SIZE;
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+
+framesize = get_framesize(common, cc, NULL, FALSE, &needs_control_head);
+BACKTRACK_AS(bracketpos_backtrack)->framesize = framesize;
+if (framesize < 0)
+ {
+ if (offset != 0)
+ {
+ stacksize = 2;
+ if (common->capture_last_ptr != 0)
+ stacksize++;
+ }
+ else
+ stacksize = 1;
+
+ if (needs_control_head)
+ stacksize++;
+ if (!zero)
+ stacksize++;
+
+ BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize;
+ allocate_stack(common, stacksize);
+ if (framesize == no_frame)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0);
+
+ stack = 0;
+ if (offset != 0)
+ {
+ stack = 2;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+ if (common->capture_last_ptr != 0)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), TMP2, 0);
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ if (common->capture_last_ptr != 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), TMP1, 0);
+ stack = 3;
+ }
+ }
+ else
+ {
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ stack = 1;
+ }
+
+ if (needs_control_head)
+ stack++;
+ if (!zero)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), SLJIT_IMM, 1);
+ if (needs_control_head)
+ {
+ stack--;
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0);
+ }
+ }
+else
+ {
+ stacksize = framesize + 1;
+ if (!zero)
+ stacksize++;
+ if (needs_control_head)
+ stacksize++;
+ if (offset == 0)
+ stacksize++;
+ BACKTRACK_AS(bracketpos_backtrack)->stacksize = stacksize;
+
+ allocate_stack(common, stacksize);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ if (needs_control_head)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), private_data_ptr, STACK_TOP, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+
+ stack = 0;
+ if (!zero)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 1);
+ stack = 1;
+ }
+ if (needs_control_head)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP2, 0);
+ stack++;
+ }
+ if (offset == 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), STR_PTR, 0);
+ stack++;
+ }
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stack), TMP1, 0);
+ init_frame(common, cc, NULL, stacksize - 1, stacksize - framesize);
+ stack -= 1 + (offset == 0);
+ }
+
+if (offset != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
+
+loop = LABEL();
+while (*cc != OP_KETRPOS)
+ {
+ backtrack->top = NULL;
+ backtrack->topbacktracks = NULL;
+ cc += GET(cc, 1);
+
+ compile_matchingpath(common, ccbegin, cc, backtrack);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+
+ if (framesize < 0)
+ {
+ if (framesize == no_frame)
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+
+ if (offset != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
+ if (common->capture_last_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+ }
+ else
+ {
+ if (opcode == OP_SBRAPOS)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ }
+
+ /* Even if the match is empty, we need to reset the control head. */
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
+
+ if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
+ add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
+
+ if (!zero)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
+ }
+ else
+ {
+ if (offset != 0)
+ {
+ OP2(SLJIT_SUB, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), cbraprivptr, STR_PTR, 0);
+ if (common->capture_last_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, offset >> 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP2(SLJIT_SUB, STACK_TOP, 0, TMP2, 0, SLJIT_IMM, stacksize * sizeof(sljit_sw));
+ if (opcode == OP_SBRAPOS)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2));
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(-framesize - 2), STR_PTR, 0);
+ }
+
+ /* Even if the match is empty, we need to reset the control head. */
+ if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_MEM1(STACK_TOP), STACK(stack));
+
+ if (opcode == OP_SBRAPOS || opcode == OP_SCBRAPOS)
+ add_jump(compiler, &emptymatch, CMP(SLJIT_EQUAL, TMP1, 0, STR_PTR, 0));
+
+ if (!zero)
+ {
+ if (framesize < 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0);
+ else
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ }
+ }
+
+ JUMPTO(SLJIT_JUMP, loop);
+ flush_stubs(common);
+
+ compile_backtrackingpath(common, backtrack->top);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return NULL;
+ set_jumps(backtrack->topbacktracks, LABEL());
+
+ if (framesize < 0)
+ {
+ if (offset != 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+ else
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ }
+ else
+ {
+ if (offset != 0)
+ {
+ /* Last alternative. */
+ if (*cc == OP_KETRPOS)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), cbraprivptr);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP2), STACK(-framesize - 2));
+ }
+ }
+
+ if (*cc == OP_KETRPOS)
+ break;
+ ccbegin = cc + 1 + LINK_SIZE;
+ }
+
+/* We don't have to restore the control head in case of a failed match. */
+
+backtrack->topbacktracks = NULL;
+if (!zero)
+ {
+ if (framesize < 0)
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(stacksize - 1), SLJIT_IMM, 0));
+ else /* TMP2 is set to [private_data_ptr] above. */
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(TMP2), STACK(-stacksize), SLJIT_IMM, 0));
+ }
+
+/* None of them matched. */
+set_jumps(emptymatch, LABEL());
+count_match(common);
+return cc + 1 + LINK_SIZE;
+}
+
+static SLJIT_INLINE PCRE2_SPTR get_iterator_parameters(compiler_common *common, PCRE2_SPTR cc, PCRE2_UCHAR *opcode, PCRE2_UCHAR *type, sljit_u32 *max, sljit_u32 *exact, PCRE2_SPTR *end)
+{
+int class_len;
+
+*opcode = *cc;
+*exact = 0;
+
+if (*opcode >= OP_STAR && *opcode <= OP_POSUPTO)
+ {
+ cc++;
+ *type = OP_CHAR;
+ }
+else if (*opcode >= OP_STARI && *opcode <= OP_POSUPTOI)
+ {
+ cc++;
+ *type = OP_CHARI;
+ *opcode -= OP_STARI - OP_STAR;
+ }
+else if (*opcode >= OP_NOTSTAR && *opcode <= OP_NOTPOSUPTO)
+ {
+ cc++;
+ *type = OP_NOT;
+ *opcode -= OP_NOTSTAR - OP_STAR;
+ }
+else if (*opcode >= OP_NOTSTARI && *opcode <= OP_NOTPOSUPTOI)
+ {
+ cc++;
+ *type = OP_NOTI;
+ *opcode -= OP_NOTSTARI - OP_STAR;
+ }
+else if (*opcode >= OP_TYPESTAR && *opcode <= OP_TYPEPOSUPTO)
+ {
+ cc++;
+ *opcode -= OP_TYPESTAR - OP_STAR;
+ *type = OP_END;
+ }
+else
+ {
+ SLJIT_ASSERT(*opcode == OP_CLASS || *opcode == OP_NCLASS || *opcode == OP_XCLASS);
+ *type = *opcode;
+ cc++;
+ class_len = (*type < OP_XCLASS) ? (int)(1 + (32 / sizeof(PCRE2_UCHAR))) : GET(cc, 0);
+ *opcode = cc[class_len - 1];
+
+ if (*opcode >= OP_CRSTAR && *opcode <= OP_CRMINQUERY)
+ {
+ *opcode -= OP_CRSTAR - OP_STAR;
+ *end = cc + class_len;
+
+ if (*opcode == OP_PLUS || *opcode == OP_MINPLUS)
+ {
+ *exact = 1;
+ *opcode -= OP_PLUS - OP_STAR;
+ }
+ }
+ else if (*opcode >= OP_CRPOSSTAR && *opcode <= OP_CRPOSQUERY)
+ {
+ *opcode -= OP_CRPOSSTAR - OP_POSSTAR;
+ *end = cc + class_len;
+
+ if (*opcode == OP_POSPLUS)
+ {
+ *exact = 1;
+ *opcode = OP_POSSTAR;
+ }
+ }
+ else
+ {
+ SLJIT_ASSERT(*opcode == OP_CRRANGE || *opcode == OP_CRMINRANGE || *opcode == OP_CRPOSRANGE);
+ *max = GET2(cc, (class_len + IMM2_SIZE));
+ *exact = GET2(cc, class_len);
+
+ if (*max == 0)
+ {
+ if (*opcode == OP_CRPOSRANGE)
+ *opcode = OP_POSSTAR;
+ else
+ *opcode -= OP_CRRANGE - OP_STAR;
+ }
+ else
+ {
+ *max -= *exact;
+ if (*max == 0)
+ *opcode = OP_EXACT;
+ else if (*max == 1)
+ {
+ if (*opcode == OP_CRPOSRANGE)
+ *opcode = OP_POSQUERY;
+ else
+ *opcode -= OP_CRRANGE - OP_QUERY;
+ }
+ else
+ {
+ if (*opcode == OP_CRPOSRANGE)
+ *opcode = OP_POSUPTO;
+ else
+ *opcode -= OP_CRRANGE - OP_UPTO;
+ }
+ }
+ *end = cc + class_len + 2 * IMM2_SIZE;
+ }
+ return cc;
+ }
+
+switch(*opcode)
+ {
+ case OP_EXACT:
+ *exact = GET2(cc, 0);
+ cc += IMM2_SIZE;
+ break;
+
+ case OP_PLUS:
+ case OP_MINPLUS:
+ *exact = 1;
+ *opcode -= OP_PLUS - OP_STAR;
+ break;
+
+ case OP_POSPLUS:
+ *exact = 1;
+ *opcode = OP_POSSTAR;
+ break;
+
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
+ *max = GET2(cc, 0);
+ cc += IMM2_SIZE;
+ break;
+ }
+
+if (*type == OP_END)
+ {
+ *type = *cc;
+ *end = next_opcode(common, cc);
+ cc++;
+ return cc;
+ }
+
+*end = cc + 1;
+#ifdef SUPPORT_UNICODE
+if (common->utf && HAS_EXTRALEN(*cc)) *end += GET_EXTRALEN(*cc);
+#endif
+return cc;
+}
+
+static PCRE2_SPTR compile_iterator_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR type;
+sljit_u32 max = 0, exact;
+BOOL fast_fail;
+sljit_s32 fast_str_ptr;
+BOOL charpos_enabled;
+PCRE2_UCHAR charpos_char;
+unsigned int charpos_othercasebit;
+PCRE2_SPTR end;
+jump_list *no_match = NULL;
+jump_list *no_char1_match = NULL;
+struct sljit_jump *jump = NULL;
+struct sljit_label *label;
+int private_data_ptr = PRIVATE_DATA(cc);
+int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
+int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
+int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
+int tmp_base, tmp_offset;
+
+PUSH_BACKTRACK(sizeof(char_iterator_backtrack), cc, NULL);
+
+fast_str_ptr = PRIVATE_DATA(cc + 1);
+fast_fail = TRUE;
+
+SLJIT_ASSERT(common->fast_forward_bc_ptr == NULL || fast_str_ptr == 0 || cc == common->fast_forward_bc_ptr);
+
+if (cc == common->fast_forward_bc_ptr)
+ fast_fail = FALSE;
+else if (common->fast_fail_start_ptr == 0)
+ fast_str_ptr = 0;
+
+SLJIT_ASSERT(common->fast_forward_bc_ptr != NULL || fast_str_ptr == 0
+ || (fast_str_ptr >= common->fast_fail_start_ptr && fast_str_ptr <= common->fast_fail_end_ptr));
+
+cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
+
+if (type != OP_EXTUNI)
+ {
+ tmp_base = TMP3;
+ tmp_offset = 0;
+ }
+else
+ {
+ tmp_base = SLJIT_MEM1(SLJIT_SP);
+ tmp_offset = POSSESSIVE0;
+ }
+
+if (fast_fail && fast_str_ptr != 0)
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), fast_str_ptr));
+
+/* Handle fixed part first. */
+if (exact > 1)
+ {
+ SLJIT_ASSERT(fast_str_ptr == 0);
+ if (common->mode == PCRE2_JIT_COMPLETE
+#ifdef SUPPORT_UNICODE
+ && !common->utf
+#endif
+ )
+ {
+ OP2(SLJIT_ADD, TMP1, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(exact));
+ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_GREATER, TMP1, 0, STR_END, 0));
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, exact);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ }
+else if (exact == 1)
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, TRUE);
+
+switch(opcode)
+ {
+ case OP_STAR:
+ case OP_UPTO:
+ SLJIT_ASSERT(fast_str_ptr == 0 || opcode == OP_STAR);
+
+ if (type == OP_ANYNL || type == OP_EXTUNI)
+ {
+ SLJIT_ASSERT(private_data_ptr == 0);
+ SLJIT_ASSERT(fast_str_ptr == 0);
+
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, 0);
+
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, SLJIT_IMM, max);
+
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
+ if (opcode == OP_UPTO)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ jump = JUMP(SLJIT_ZERO);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE0, TMP1, 0);
+ }
+
+ /* We cannot use TMP3 because of this allocate_stack. */
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, label);
+ if (jump != NULL)
+ JUMPHERE(jump);
+ }
+ else
+ {
+ charpos_enabled = FALSE;
+ charpos_char = 0;
+ charpos_othercasebit = 0;
+
+ if ((type != OP_CHAR && type != OP_CHARI) && (*end == OP_CHAR || *end == OP_CHARI))
+ {
+ charpos_enabled = TRUE;
+#ifdef SUPPORT_UNICODE
+ charpos_enabled = !common->utf || !HAS_EXTRALEN(end[1]);
+#endif
+ if (charpos_enabled && *end == OP_CHARI && char_has_othercase(common, end + 1))
+ {
+ charpos_othercasebit = char_get_othercase_bit(common, end + 1);
+ if (charpos_othercasebit == 0)
+ charpos_enabled = FALSE;
+ }
+
+ if (charpos_enabled)
+ {
+ charpos_char = end[1];
+ /* Consumpe the OP_CHAR opcode. */
+ end += 2;
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ SLJIT_ASSERT((charpos_othercasebit >> 8) == 0);
+#elif PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ SLJIT_ASSERT((charpos_othercasebit >> 9) == 0);
+ if ((charpos_othercasebit & 0x100) != 0)
+ charpos_othercasebit = (charpos_othercasebit & 0xff) << 8;
+#endif
+ if (charpos_othercasebit != 0)
+ charpos_char |= charpos_othercasebit;
+
+ BACKTRACK_AS(char_iterator_backtrack)->u.charpos.enabled = TRUE;
+ BACKTRACK_AS(char_iterator_backtrack)->u.charpos.chr = charpos_char;
+ BACKTRACK_AS(char_iterator_backtrack)->u.charpos.othercasebit = charpos_othercasebit;
+ }
+ }
+
+ if (charpos_enabled)
+ {
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max + 1);
+
+ /* Search the first instance of charpos_char. */
+ jump = JUMP(SLJIT_JUMP);
+ label = LABEL();
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_ZERO));
+ }
+ compile_char1_matchingpath(common, type, cc, &backtrack->topbacktracks, FALSE);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ JUMPHERE(jump);
+
+ detect_partial_match(common, &backtrack->topbacktracks);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (charpos_othercasebit != 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label);
+
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ add_jump(compiler, &no_match, JUMP(SLJIT_ZERO));
+ }
+
+ /* Search the last instance of charpos_char. */
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, FALSE);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ detect_partial_match(common, &no_match);
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(0));
+ if (charpos_othercasebit != 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, charpos_othercasebit);
+ if (opcode == OP_STAR)
+ {
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char, label);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ }
+ else
+ {
+ jump = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, charpos_char);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+ JUMPTO(SLJIT_JUMP, label);
+
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ }
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ else if (common->utf)
+ {
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ }
+ else
+ JUMPTO(SLJIT_JUMP, label);
+
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ }
+#endif
+ else
+ {
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+
+ OP1(SLJIT_MOV, base, offset1, STR_PTR, 0);
+ if (opcode == OP_UPTO)
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+
+ label = LABEL();
+ detect_partial_match(common, &no_match);
+ compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+ if (opcode == OP_UPTO)
+ {
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+ else
+ JUMPTO(SLJIT_JUMP, label);
+
+ set_jumps(no_char1_match, LABEL());
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ }
+ }
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+ break;
+
+ case OP_MINSTAR:
+ if (private_data_ptr == 0)
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ break;
+
+ case OP_MINUPTO:
+ SLJIT_ASSERT(fast_str_ptr == 0);
+ if (private_data_ptr == 0)
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ OP1(SLJIT_MOV, base, offset1, SLJIT_IMM, max + 1);
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+ break;
+
+ case OP_QUERY:
+ case OP_MINQUERY:
+ SLJIT_ASSERT(fast_str_ptr == 0);
+ if (private_data_ptr == 0)
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ if (opcode == OP_QUERY)
+ compile_char1_matchingpath(common, type, cc, &BACKTRACK_AS(char_iterator_backtrack)->u.backtracks, TRUE);
+ BACKTRACK_AS(char_iterator_backtrack)->matchingpath = LABEL();
+ break;
+
+ case OP_EXACT:
+ break;
+
+ case OP_POSSTAR:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf)
+ {
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, label);
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ break;
+ }
+#endif
+ label = LABEL();
+ detect_partial_match(common, &no_match);
+ compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+ JUMPTO(SLJIT_JUMP, label);
+ set_jumps(no_char1_match, LABEL());
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_match, LABEL());
+ if (fast_str_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), fast_str_ptr, STR_PTR, 0);
+ break;
+
+ case OP_POSUPTO:
+ SLJIT_ASSERT(fast_str_ptr == 0);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 32
+ if (common->utf)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+ label = LABEL();
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1, STR_PTR, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), POSSESSIVE1);
+ break;
+ }
+#endif
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, SLJIT_IMM, max);
+ label = LABEL();
+ detect_partial_match(common, &no_match);
+ compile_char1_matchingpath(common, type, cc, &no_char1_match, FALSE);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, tmp_base, tmp_offset, tmp_base, tmp_offset, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, label);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_char1_match, LABEL());
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ set_jumps(no_match, LABEL());
+ break;
+
+ case OP_POSQUERY:
+ SLJIT_ASSERT(fast_str_ptr == 0);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+ compile_char1_matchingpath(common, type, cc, &no_match, TRUE);
+ OP1(SLJIT_MOV, tmp_base, tmp_offset, STR_PTR, 0);
+ set_jumps(no_match, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, tmp_base, tmp_offset);
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+
+count_match(common);
+return end;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_fail_accept_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+
+PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
+
+if (*cc == OP_FAIL)
+ {
+ add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
+ return cc + 1;
+ }
+
+if (*cc == OP_ACCEPT && common->currententry == NULL && (common->re->overall_options & PCRE2_ENDANCHORED) != 0)
+ add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0));
+
+if (*cc == OP_ASSERT_ACCEPT || common->currententry != NULL || !common->might_be_empty)
+ {
+ /* No need to check notempty conditions. */
+ if (common->accept_label == NULL)
+ add_jump(compiler, &common->accept, JUMP(SLJIT_JUMP));
+ else
+ JUMPTO(SLJIT_JUMP, common->accept_label);
+ return cc + 1;
+ }
+
+if (common->accept_label == NULL)
+ add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0)));
+else
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), common->accept_label);
+OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options));
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_NOT_ZERO));
+OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
+if (common->accept_label == NULL)
+ add_jump(compiler, &common->accept, JUMP(SLJIT_ZERO));
+else
+ JUMPTO(SLJIT_ZERO, common->accept_label);
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+if (common->accept_label == NULL)
+ add_jump(compiler, &common->accept, CMP(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0));
+else
+ CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, common->accept_label);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_JUMP));
+return cc + 1;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_close_matchingpath(compiler_common *common, PCRE2_SPTR cc)
+{
+DEFINE_COMPILER;
+int offset = GET2(cc, 1);
+BOOL optimized_cbracket = common->optimized_cbracket[offset] != 0;
+
+/* Data will be discarded anyway... */
+if (common->currententry != NULL)
+ return cc + 1 + IMM2_SIZE;
+
+if (!optimized_cbracket)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR_PRIV(offset));
+offset <<= 1;
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+if (!optimized_cbracket)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+return cc + 1 + IMM2_SIZE;
+}
+
+static SLJIT_INLINE PCRE2_SPTR compile_control_verb_matchingpath(compiler_common *common, PCRE2_SPTR cc, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+PCRE2_UCHAR opcode = *cc;
+PCRE2_SPTR ccend = cc + 1;
+
+if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG ||
+ opcode == OP_SKIP_ARG || opcode == OP_THEN_ARG)
+ ccend += 2 + cc[1];
+
+PUSH_BACKTRACK(sizeof(backtrack_common), cc, NULL);
+
+if (opcode == OP_SKIP)
+ {
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ return ccend;
+ }
+
+if (opcode == OP_COMMIT_ARG || opcode == OP_PRUNE_ARG || opcode == OP_THEN_ARG)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0);
+ }
+
+return ccend;
+}
+
+static PCRE2_UCHAR then_trap_opcode[1] = { OP_THEN_TRAP };
+
+static SLJIT_INLINE void compile_then_trap_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+BOOL needs_control_head;
+int size;
+
+PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc);
+common->then_trap = BACKTRACK_AS(then_trap_backtrack);
+BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode;
+BACKTRACK_AS(then_trap_backtrack)->start = (sljit_sw)(cc - common->start);
+BACKTRACK_AS(then_trap_backtrack)->framesize = get_framesize(common, cc, ccend, FALSE, &needs_control_head);
+
+size = BACKTRACK_AS(then_trap_backtrack)->framesize;
+size = 3 + (size < 0 ? 0 : size);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+allocate_stack(common, size);
+if (size > 3)
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0, SLJIT_IMM, (size - 3) * sizeof(sljit_sw));
+else
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 1), SLJIT_IMM, BACKTRACK_AS(then_trap_backtrack)->start);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 2), SLJIT_IMM, type_then_trap);
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(size - 3), TMP2, 0);
+
+size = BACKTRACK_AS(then_trap_backtrack)->framesize;
+if (size >= 0)
+ init_frame(common, cc, ccend, size - 1, 0);
+}
+
+static void compile_matchingpath(compiler_common *common, PCRE2_SPTR cc, PCRE2_SPTR ccend, backtrack_common *parent)
+{
+DEFINE_COMPILER;
+backtrack_common *backtrack;
+BOOL has_then_trap = FALSE;
+then_trap_backtrack *save_then_trap = NULL;
+
+SLJIT_ASSERT(*ccend == OP_END || (*ccend >= OP_ALT && *ccend <= OP_KETRPOS));
+
+if (common->has_then && common->then_offsets[cc - common->start] != 0)
+ {
+ SLJIT_ASSERT(*ccend != OP_END && common->control_head_ptr != 0);
+ has_then_trap = TRUE;
+ save_then_trap = common->then_trap;
+ /* Tail item on backtrack. */
+ compile_then_trap_matchingpath(common, cc, ccend, parent);
+ }
+
+while (cc < ccend)
+ {
+ switch(*cc)
+ {
+ case OP_SOD:
+ case OP_SOM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ case OP_EODN:
+ case OP_EOD:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_REVERSE:
+ cc = compile_simple_assertion_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ break;
+
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_ANYBYTE:
+ case OP_NOTPROP:
+ case OP_PROP:
+ case OP_ANYNL:
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ case OP_EXTUNI:
+ case OP_NOT:
+ case OP_NOTI:
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+ break;
+
+ case OP_SET_SOM:
+ PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+ cc++;
+ break;
+
+ case OP_CHAR:
+ case OP_CHARI:
+ if (common->mode == PCRE2_JIT_COMPLETE)
+ cc = compile_charn_matchingpath(common, cc, ccend, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ else
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+ break;
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ case OP_TYPEPOSUPTO:
+ cc = compile_iterator_matchingpath(common, cc, parent);
+ break;
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ if (cc[1 + (32 / sizeof(PCRE2_UCHAR))] >= OP_CRSTAR && cc[1 + (32 / sizeof(PCRE2_UCHAR))] <= OP_CRPOSRANGE)
+ cc = compile_iterator_matchingpath(common, cc, parent);
+ else
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+ break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH == 16 || PCRE2_CODE_UNIT_WIDTH == 32
+ case OP_XCLASS:
+ if (*(cc + GET(cc, 1)) >= OP_CRSTAR && *(cc + GET(cc, 1)) <= OP_CRPOSRANGE)
+ cc = compile_iterator_matchingpath(common, cc, parent);
+ else
+ cc = compile_char1_matchingpath(common, *cc, cc + 1, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE);
+ break;
+#endif
+
+ case OP_REF:
+ case OP_REFI:
+ if (cc[1 + IMM2_SIZE] >= OP_CRSTAR && cc[1 + IMM2_SIZE] <= OP_CRPOSRANGE)
+ cc = compile_ref_iterator_matchingpath(common, cc, parent);
+ else
+ {
+ compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE);
+ cc += 1 + IMM2_SIZE;
+ }
+ break;
+
+ case OP_DNREF:
+ case OP_DNREFI:
+ if (cc[1 + 2 * IMM2_SIZE] >= OP_CRSTAR && cc[1 + 2 * IMM2_SIZE] <= OP_CRPOSRANGE)
+ cc = compile_ref_iterator_matchingpath(common, cc, parent);
+ else
+ {
+ compile_dnref_search(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks);
+ compile_ref_matchingpath(common, cc, parent->top != NULL ? &parent->top->nextbacktracks : &parent->topbacktracks, TRUE, FALSE);
+ cc += 1 + 2 * IMM2_SIZE;
+ }
+ break;
+
+ case OP_RECURSE:
+ cc = compile_recurse_matchingpath(common, cc, parent);
+ break;
+
+ case OP_CALLOUT:
+ case OP_CALLOUT_STR:
+ cc = compile_callout_matchingpath(common, cc, parent);
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc);
+ cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE);
+ break;
+
+ case OP_BRAMINZERO:
+ PUSH_BACKTRACK_NOVALUE(sizeof(braminzero_backtrack), cc);
+ cc = bracketend(cc + 1);
+ if (*(cc - 1 - LINK_SIZE) != OP_KETRMIN)
+ {
+ allocate_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+ }
+ else
+ {
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), STR_PTR, 0);
+ }
+ BACKTRACK_AS(braminzero_backtrack)->matchingpath = LABEL();
+ count_match(common);
+ break;
+
+ case OP_ONCE:
+ case OP_BRA:
+ case OP_CBRA:
+ case OP_COND:
+ case OP_SBRA:
+ case OP_SCBRA:
+ case OP_SCOND:
+ cc = compile_bracket_matchingpath(common, cc, parent);
+ break;
+
+ case OP_BRAZERO:
+ if (cc[1] > OP_ASSERTBACK_NOT)
+ cc = compile_bracket_matchingpath(common, cc, parent);
+ else
+ {
+ PUSH_BACKTRACK_NOVALUE(sizeof(assert_backtrack), cc);
+ cc = compile_assert_matchingpath(common, cc, BACKTRACK_AS(assert_backtrack), FALSE);
+ }
+ break;
+
+ case OP_BRAPOS:
+ case OP_CBRAPOS:
+ case OP_SBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_BRAPOSZERO:
+ cc = compile_bracketpos_matchingpath(common, cc, parent);
+ break;
+
+ case OP_MARK:
+ PUSH_BACKTRACK_NOVALUE(sizeof(backtrack_common), cc);
+ SLJIT_ASSERT(common->mark_ptr != 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->mark_ptr);
+ allocate_stack(common, common->has_skip_arg ? 5 : 1);
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0), TMP2, 0);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, (sljit_sw)(cc + 2));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, mark_ptr), TMP2, 0);
+ if (common->has_skip_arg)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, STACK_TOP, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, type_mark);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(2), SLJIT_IMM, (sljit_sw)(cc + 2));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(3), STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP1, 0);
+ }
+ cc += 1 + 2 + cc[1];
+ break;
+
+ case OP_PRUNE:
+ case OP_PRUNE_ARG:
+ case OP_SKIP:
+ case OP_SKIP_ARG:
+ case OP_THEN:
+ case OP_THEN_ARG:
+ case OP_COMMIT:
+ case OP_COMMIT_ARG:
+ cc = compile_control_verb_matchingpath(common, cc, parent);
+ break;
+
+ case OP_FAIL:
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ cc = compile_fail_accept_matchingpath(common, cc, parent);
+ break;
+
+ case OP_CLOSE:
+ cc = compile_close_matchingpath(common, cc);
+ break;
+
+ case OP_SKIPZERO:
+ cc = bracketend(cc + 1);
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ return;
+ }
+ if (cc == NULL)
+ return;
+ }
+
+if (has_then_trap)
+ {
+ /* Head item on backtrack. */
+ PUSH_BACKTRACK_NOVALUE(sizeof(then_trap_backtrack), cc);
+ BACKTRACK_AS(then_trap_backtrack)->common.cc = then_trap_opcode;
+ BACKTRACK_AS(then_trap_backtrack)->then_trap = common->then_trap;
+ common->then_trap = save_then_trap;
+ }
+SLJIT_ASSERT(cc == ccend);
+}
+
+#undef PUSH_BACKTRACK
+#undef PUSH_BACKTRACK_NOVALUE
+#undef BACKTRACK_AS
+
+#define COMPILE_BACKTRACKINGPATH(current) \
+ do \
+ { \
+ compile_backtrackingpath(common, (current)); \
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler))) \
+ return; \
+ } \
+ while (0)
+
+#define CURRENT_AS(type) ((type *)current)
+
+static void compile_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = current->cc;
+PCRE2_UCHAR opcode;
+PCRE2_UCHAR type;
+sljit_u32 max = 0, exact;
+struct sljit_label *label = NULL;
+struct sljit_jump *jump = NULL;
+jump_list *jumplist = NULL;
+PCRE2_SPTR end;
+int private_data_ptr = PRIVATE_DATA(cc);
+int base = (private_data_ptr == 0) ? SLJIT_MEM1(STACK_TOP) : SLJIT_MEM1(SLJIT_SP);
+int offset0 = (private_data_ptr == 0) ? STACK(0) : private_data_ptr;
+int offset1 = (private_data_ptr == 0) ? STACK(1) : private_data_ptr + (int)sizeof(sljit_sw);
+
+cc = get_iterator_parameters(common, cc, &opcode, &type, &max, &exact, &end);
+
+switch(opcode)
+ {
+ case OP_STAR:
+ case OP_UPTO:
+ if (type == OP_ANYNL || type == OP_EXTUNI)
+ {
+ SLJIT_ASSERT(private_data_ptr == 0);
+ set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ }
+ else
+ {
+ if (CURRENT_AS(char_iterator_backtrack)->u.charpos.enabled)
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP1(SLJIT_MOV, TMP2, 0, base, offset1);
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, TMP2, 0);
+ label = LABEL();
+ OP1(MOV_UCHAR, TMP1, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(-1));
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ if (CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit != 0)
+ OP2(SLJIT_OR, TMP1, 0, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.othercasebit);
+ CMPTO(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, CURRENT_AS(char_iterator_backtrack)->u.charpos.chr, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ skip_char_back(common);
+ CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP2, 0, label);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ jump = CMP(SLJIT_LESS_EQUAL, STR_PTR, 0, base, offset1);
+ skip_char_back(common);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ }
+ JUMPHERE(jump);
+ if (private_data_ptr == 0)
+ free_stack(common, 2);
+ }
+ break;
+
+ case OP_MINSTAR:
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ set_jumps(jumplist, LABEL());
+ if (private_data_ptr == 0)
+ free_stack(common, 1);
+ break;
+
+ case OP_MINUPTO:
+ OP1(SLJIT_MOV, TMP1, 0, base, offset1);
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+ add_jump(compiler, &jumplist, JUMP(SLJIT_ZERO));
+
+ OP1(SLJIT_MOV, base, offset1, TMP1, 0);
+ compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+ OP1(SLJIT_MOV, base, offset0, STR_PTR, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+
+ set_jumps(jumplist, LABEL());
+ if (private_data_ptr == 0)
+ free_stack(common, 2);
+ break;
+
+ case OP_QUERY:
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ jump = JUMP(SLJIT_JUMP);
+ set_jumps(CURRENT_AS(char_iterator_backtrack)->u.backtracks, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ JUMPHERE(jump);
+ if (private_data_ptr == 0)
+ free_stack(common, 1);
+ break;
+
+ case OP_MINQUERY:
+ OP1(SLJIT_MOV, STR_PTR, 0, base, offset0);
+ OP1(SLJIT_MOV, base, offset0, SLJIT_IMM, 0);
+ jump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+ compile_char1_matchingpath(common, type, cc, &jumplist, TRUE);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(char_iterator_backtrack)->matchingpath);
+ set_jumps(jumplist, LABEL());
+ JUMPHERE(jump);
+ if (private_data_ptr == 0)
+ free_stack(common, 1);
+ break;
+
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+
+set_jumps(current->topbacktracks, LABEL());
+}
+
+static SLJIT_INLINE void compile_ref_iterator_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = current->cc;
+BOOL ref = (*cc == OP_REF || *cc == OP_REFI);
+PCRE2_UCHAR type;
+
+type = cc[ref ? 1 + IMM2_SIZE : 1 + 2 * IMM2_SIZE];
+
+if ((type & 0x1) == 0)
+ {
+ /* Maximize case. */
+ set_jumps(current->topbacktracks, LABEL());
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
+ return;
+ }
+
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(ref_iterator_backtrack)->matchingpath);
+set_jumps(current->topbacktracks, LABEL());
+free_stack(common, ref ? 2 : 3);
+}
+
+static SLJIT_INLINE void compile_recurse_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+recurse_entry *entry;
+
+if (!CURRENT_AS(recurse_backtrack)->inlined_pattern)
+ {
+ entry = CURRENT_AS(recurse_backtrack)->entry;
+ if (entry->backtrack_label == NULL)
+ add_jump(compiler, &entry->backtrack_calls, JUMP(SLJIT_FAST_CALL));
+ else
+ JUMPTO(SLJIT_FAST_CALL, entry->backtrack_label);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(recurse_backtrack)->matchingpath);
+ }
+else
+ compile_backtrackingpath(common, current->top);
+
+set_jumps(current->topbacktracks, LABEL());
+}
+
+static void compile_assert_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = current->cc;
+PCRE2_UCHAR bra = OP_BRA;
+struct sljit_jump *brajump = NULL;
+
+SLJIT_ASSERT(*cc != OP_BRAMINZERO);
+if (*cc == OP_BRAZERO)
+ {
+ bra = *cc;
+ cc++;
+ }
+
+if (bra == OP_BRAZERO)
+ {
+ SLJIT_ASSERT(current->topbacktracks == NULL);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ }
+
+if (CURRENT_AS(assert_backtrack)->framesize < 0)
+ {
+ set_jumps(current->topbacktracks, LABEL());
+
+ if (bra == OP_BRAZERO)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath);
+ free_stack(common, 1);
+ }
+ return;
+ }
+
+if (bra == OP_BRAZERO)
+ {
+ if (*cc == OP_ASSERT_NOT || *cc == OP_ASSERTBACK_NOT)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(assert_backtrack)->matchingpath);
+ free_stack(common, 1);
+ return;
+ }
+ free_stack(common, 1);
+ brajump = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0);
+ }
+
+if (*cc == OP_ASSERT || *cc == OP_ASSERTBACK)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(assert_backtrack)->framesize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(assert_backtrack)->private_data_ptr, TMP1, 0);
+
+ set_jumps(current->topbacktracks, LABEL());
+ }
+else
+ set_jumps(current->topbacktracks, LABEL());
+
+if (bra == OP_BRAZERO)
+ {
+ /* We know there is enough place on the stack. */
+ OP2(SLJIT_SUB, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), SLJIT_IMM, 0);
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(assert_backtrack)->matchingpath);
+ JUMPHERE(brajump);
+ }
+}
+
+static void compile_bracket_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+int opcode, stacksize, alt_count, alt_max;
+int offset = 0;
+int private_data_ptr = CURRENT_AS(bracket_backtrack)->private_data_ptr;
+int repeat_ptr = 0, repeat_type = 0, repeat_count = 0;
+PCRE2_SPTR cc = current->cc;
+PCRE2_SPTR ccbegin;
+PCRE2_SPTR ccprev;
+PCRE2_UCHAR bra = OP_BRA;
+PCRE2_UCHAR ket;
+assert_backtrack *assert;
+sljit_uw *next_update_addr = NULL;
+BOOL has_alternatives;
+BOOL needs_control_head = FALSE;
+struct sljit_jump *brazero = NULL;
+struct sljit_jump *alt1 = NULL;
+struct sljit_jump *alt2 = NULL;
+struct sljit_jump *once = NULL;
+struct sljit_jump *cond = NULL;
+struct sljit_label *rmin_label = NULL;
+struct sljit_label *exact_label = NULL;
+
+if (*cc == OP_BRAZERO || *cc == OP_BRAMINZERO)
+ {
+ bra = *cc;
+ cc++;
+ }
+
+opcode = *cc;
+ccbegin = bracketend(cc) - 1 - LINK_SIZE;
+ket = *ccbegin;
+if (ket == OP_KET && PRIVATE_DATA(ccbegin) != 0)
+ {
+ repeat_ptr = PRIVATE_DATA(ccbegin);
+ repeat_type = PRIVATE_DATA(ccbegin + 2);
+ repeat_count = PRIVATE_DATA(ccbegin + 3);
+ SLJIT_ASSERT(repeat_type != 0 && repeat_count != 0);
+ if (repeat_type == OP_UPTO)
+ ket = OP_KETRMAX;
+ if (repeat_type == OP_MINUPTO)
+ ket = OP_KETRMIN;
+ }
+ccbegin = cc;
+cc += GET(cc, 1);
+has_alternatives = *cc == OP_ALT;
+if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
+ has_alternatives = (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT) || CURRENT_AS(bracket_backtrack)->u.condfailed != NULL;
+if (opcode == OP_CBRA || opcode == OP_SCBRA)
+ offset = (GET2(ccbegin, 1 + LINK_SIZE)) << 1;
+if (SLJIT_UNLIKELY(opcode == OP_COND) && (*cc == OP_KETRMAX || *cc == OP_KETRMIN))
+ opcode = OP_SCOND;
+
+alt_max = has_alternatives ? no_alternatives(ccbegin) : 0;
+
+/* Decoding the needs_control_head in framesize. */
+if (opcode == OP_ONCE)
+ {
+ needs_control_head = (CURRENT_AS(bracket_backtrack)->u.framesize & 0x1) != 0;
+ CURRENT_AS(bracket_backtrack)->u.framesize >>= 1;
+ }
+
+if (ket != OP_KET && repeat_type != 0)
+ {
+ /* TMP1 is used in OP_KETRMIN below. */
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ if (repeat_type == OP_UPTO)
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0, SLJIT_IMM, 1);
+ else
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0);
+ }
+
+if (ket == OP_KETRMAX)
+ {
+ if (bra == OP_BRAZERO)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ brazero = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+ }
+ }
+else if (ket == OP_KETRMIN)
+ {
+ if (bra != OP_BRAMINZERO)
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ if (repeat_type != 0)
+ {
+ /* TMP1 was set a few lines above. */
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+ /* Drop STR_PTR for non-greedy plus quantifier. */
+ if (opcode != OP_ONCE)
+ free_stack(common, 1);
+ }
+ else if (opcode >= OP_SBRA || opcode == OP_ONCE)
+ {
+ /* Checking zero-length iteration. */
+ if (opcode != OP_ONCE || CURRENT_AS(bracket_backtrack)->u.framesize < 0)
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+ else
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_MEM1(TMP1), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 2), CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+ }
+ /* Drop STR_PTR for non-greedy plus quantifier. */
+ if (opcode != OP_ONCE)
+ free_stack(common, 1);
+ }
+ else
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+ }
+ rmin_label = LABEL();
+ if (repeat_type != 0)
+ OP2(SLJIT_ADD, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ }
+else if (bra == OP_BRAZERO)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ brazero = CMP(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0);
+ }
+else if (repeat_type == OP_EXACT)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ exact_label = LABEL();
+ }
+
+if (offset != 0)
+ {
+ if (common->capture_last_ptr != 0)
+ {
+ SLJIT_ASSERT(common->optimized_cbracket[offset >> 1] == 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+ free_stack(common, 3);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP2, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP1, 0);
+ }
+ else if (common->optimized_cbracket[offset >> 1] == 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ free_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0);
+ }
+ }
+
+if (SLJIT_UNLIKELY(opcode == OP_ONCE))
+ {
+ if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracket_backtrack)->u.framesize - 1) * sizeof(sljit_sw));
+ }
+ once = JUMP(SLJIT_JUMP);
+ }
+else if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
+ {
+ if (has_alternatives)
+ {
+ /* Always exactly one alternative. */
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+
+ alt_max = 2;
+ alt1 = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IMM, sizeof(sljit_uw));
+ }
+ }
+else if (has_alternatives)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+
+ if (alt_max > 4)
+ {
+ /* Table jump if alt_max is greater than 4. */
+ next_update_addr = allocate_read_only_data(common, alt_max * sizeof(sljit_uw));
+ if (SLJIT_UNLIKELY(next_update_addr == NULL))
+ return;
+ sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_MEM1(TMP1), (sljit_sw)next_update_addr);
+ add_label_addr(common, next_update_addr++);
+ }
+ else
+ {
+ if (alt_max == 4)
+ alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw));
+ alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, sizeof(sljit_uw));
+ }
+ }
+
+COMPILE_BACKTRACKINGPATH(current->top);
+if (current->topbacktracks)
+ set_jumps(current->topbacktracks, LABEL());
+
+if (SLJIT_UNLIKELY(opcode == OP_COND) || SLJIT_UNLIKELY(opcode == OP_SCOND))
+ {
+ /* Conditional block always has at most one alternative. */
+ if (ccbegin[1 + LINK_SIZE] >= OP_ASSERT && ccbegin[1 + LINK_SIZE] <= OP_ASSERTBACK_NOT)
+ {
+ SLJIT_ASSERT(has_alternatives);
+ assert = CURRENT_AS(bracket_backtrack)->u.assert;
+ if (assert->framesize >= 0 && (ccbegin[1 + LINK_SIZE] == OP_ASSERT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK))
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0);
+ }
+ cond = JUMP(SLJIT_JUMP);
+ set_jumps(CURRENT_AS(bracket_backtrack)->u.assert->condfailed, LABEL());
+ }
+ else if (CURRENT_AS(bracket_backtrack)->u.condfailed != NULL)
+ {
+ SLJIT_ASSERT(has_alternatives);
+ cond = JUMP(SLJIT_JUMP);
+ set_jumps(CURRENT_AS(bracket_backtrack)->u.condfailed, LABEL());
+ }
+ else
+ SLJIT_ASSERT(!has_alternatives);
+ }
+
+if (has_alternatives)
+ {
+ alt_count = sizeof(sljit_uw);
+ do
+ {
+ current->top = NULL;
+ current->topbacktracks = NULL;
+ current->nextbacktracks = NULL;
+ /* Conditional blocks always have an additional alternative, even if it is empty. */
+ if (*cc == OP_ALT)
+ {
+ ccprev = cc + 1 + LINK_SIZE;
+ cc += GET(cc, 1);
+ if (opcode != OP_COND && opcode != OP_SCOND)
+ {
+ if (opcode != OP_ONCE)
+ {
+ if (private_data_ptr != 0)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), private_data_ptr);
+ else
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ }
+ else
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(needs_control_head ? 1 : 0));
+ }
+ compile_matchingpath(common, ccprev, cc, current);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return;
+ }
+
+ /* Instructions after the current alternative is successfully matched. */
+ /* There is a similar code in compile_bracket_matchingpath. */
+ if (opcode == OP_ONCE)
+ match_once_common(common, ket, CURRENT_AS(bracket_backtrack)->u.framesize, private_data_ptr, has_alternatives, needs_control_head);
+
+ stacksize = 0;
+ if (repeat_type == OP_MINUPTO)
+ {
+ /* We need to preserve the counter. TMP2 will be used below. */
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr);
+ stacksize++;
+ }
+ if (ket != OP_KET || bra != OP_BRA)
+ stacksize++;
+ if (offset != 0)
+ {
+ if (common->capture_last_ptr != 0)
+ stacksize++;
+ if (common->optimized_cbracket[offset >> 1] == 0)
+ stacksize += 2;
+ }
+ if (opcode != OP_ONCE)
+ stacksize++;
+
+ if (stacksize > 0)
+ allocate_stack(common, stacksize);
+
+ stacksize = 0;
+ if (repeat_type == OP_MINUPTO)
+ {
+ /* TMP2 was set above. */
+ OP2(SLJIT_SUB, SLJIT_MEM1(STACK_TOP), STACK(stacksize), TMP2, 0, SLJIT_IMM, 1);
+ stacksize++;
+ }
+
+ if (ket != OP_KET || bra != OP_BRA)
+ {
+ if (ket != OP_KET)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), STR_PTR, 0);
+ else
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, 0);
+ stacksize++;
+ }
+
+ if (offset != 0)
+ stacksize = match_capture_common(common, stacksize, offset, private_data_ptr);
+
+ if (opcode != OP_ONCE)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(stacksize), SLJIT_IMM, alt_count);
+
+ if (offset != 0 && ket == OP_KETRMAX && common->optimized_cbracket[offset >> 1] != 0)
+ {
+ /* If ket is not OP_KETRMAX, this code path is executed after the jump to alternative_matchingpath. */
+ SLJIT_ASSERT(private_data_ptr == OVECTOR(offset + 0));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), STR_PTR, 0);
+ }
+
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->alternative_matchingpath);
+
+ if (opcode != OP_ONCE)
+ {
+ if (alt_max > 4)
+ add_label_addr(common, next_update_addr++);
+ else
+ {
+ if (alt_count != 2 * sizeof(sljit_uw))
+ {
+ JUMPHERE(alt1);
+ if (alt_max == 3 && alt_count == sizeof(sljit_uw))
+ alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw));
+ }
+ else
+ {
+ JUMPHERE(alt2);
+ if (alt_max == 4)
+ alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_uw));
+ }
+ }
+ alt_count += sizeof(sljit_uw);
+ }
+
+ COMPILE_BACKTRACKINGPATH(current->top);
+ if (current->topbacktracks)
+ set_jumps(current->topbacktracks, LABEL());
+ SLJIT_ASSERT(!current->nextbacktracks);
+ }
+ while (*cc == OP_ALT);
+
+ if (cond != NULL)
+ {
+ SLJIT_ASSERT(opcode == OP_COND || opcode == OP_SCOND);
+ assert = CURRENT_AS(bracket_backtrack)->u.assert;
+ if ((ccbegin[1 + LINK_SIZE] == OP_ASSERT_NOT || ccbegin[1 + LINK_SIZE] == OP_ASSERTBACK_NOT) && assert->framesize >= 0)
+ {
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr);
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(-2));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (assert->framesize - 1) * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), assert->private_data_ptr, TMP1, 0);
+ }
+ JUMPHERE(cond);
+ }
+
+ /* Free the STR_PTR. */
+ if (private_data_ptr == 0)
+ free_stack(common, 1);
+ }
+
+if (offset != 0)
+ {
+ /* Using both tmp register is better for instruction scheduling. */
+ if (common->optimized_cbracket[offset >> 1] != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ free_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0);
+ }
+ else
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ }
+ }
+else if (opcode == OP_SBRA || opcode == OP_SCOND)
+ {
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ }
+else if (opcode == OP_ONCE)
+ {
+ cc = ccbegin + GET(ccbegin, 1);
+ stacksize = needs_control_head ? 1 : 0;
+
+ if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+ {
+ /* Reset head and drop saved frame. */
+ stacksize += CURRENT_AS(bracket_backtrack)->u.framesize + ((ket != OP_KET || *cc == OP_ALT) ? 2 : 1);
+ }
+ else if (ket == OP_KETRMAX || (*cc == OP_ALT && ket != OP_KETRMIN))
+ {
+ /* The STR_PTR must be released. */
+ stacksize++;
+ }
+
+ if (stacksize > 0)
+ free_stack(common, stacksize);
+
+ JUMPHERE(once);
+ /* Restore previous private_data_ptr */
+ if (CURRENT_AS(bracket_backtrack)->u.framesize >= 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracket_backtrack)->u.framesize - 1));
+ else if (ket == OP_KETRMIN)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ /* See the comment below. */
+ free_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), private_data_ptr, TMP1, 0);
+ }
+ }
+
+if (repeat_type == OP_EXACT)
+ {
+ OP2(SLJIT_ADD, TMP1, 0, SLJIT_MEM1(SLJIT_SP), repeat_ptr, SLJIT_IMM, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), repeat_ptr, TMP1, 0);
+ CMPTO(SLJIT_LESS_EQUAL, TMP1, 0, SLJIT_IMM, repeat_count, exact_label);
+ }
+else if (ket == OP_KETRMAX)
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ if (bra != OP_BRAZERO)
+ free_stack(common, 1);
+
+ CMPTO(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0, CURRENT_AS(bracket_backtrack)->recursive_matchingpath);
+ if (bra == OP_BRAZERO)
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath);
+ JUMPHERE(brazero);
+ free_stack(common, 1);
+ }
+ }
+else if (ket == OP_KETRMIN)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+ /* OP_ONCE removes everything in case of a backtrack, so we don't
+ need to explicitly release the STR_PTR. The extra release would
+ affect badly the free_stack(2) above. */
+ if (opcode != OP_ONCE)
+ free_stack(common, 1);
+ CMPTO(SLJIT_NOT_EQUAL, TMP1, 0, SLJIT_IMM, 0, rmin_label);
+ if (opcode == OP_ONCE)
+ free_stack(common, bra == OP_BRAMINZERO ? 2 : 1);
+ else if (bra == OP_BRAMINZERO)
+ free_stack(common, 1);
+ }
+else if (bra == OP_BRAZERO)
+ {
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ JUMPTO(SLJIT_JUMP, CURRENT_AS(bracket_backtrack)->zero_matchingpath);
+ JUMPHERE(brazero);
+ }
+}
+
+static SLJIT_INLINE void compile_bracketpos_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+int offset;
+struct sljit_jump *jump;
+
+if (CURRENT_AS(bracketpos_backtrack)->framesize < 0)
+ {
+ if (*current->cc == OP_CBRAPOS || *current->cc == OP_SCBRAPOS)
+ {
+ offset = (GET2(current->cc, 1 + LINK_SIZE)) << 1;
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset), TMP1, 0);
+ if (common->capture_last_ptr != 0)
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(2));
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1), TMP2, 0);
+ if (common->capture_last_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, TMP1, 0);
+ }
+ set_jumps(current->topbacktracks, LABEL());
+ free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
+ return;
+ }
+
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr);
+add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(bracketpos_backtrack)->framesize - 1) * sizeof(sljit_sw));
+
+if (current->topbacktracks)
+ {
+ jump = JUMP(SLJIT_JUMP);
+ set_jumps(current->topbacktracks, LABEL());
+ /* Drop the stack frame. */
+ free_stack(common, CURRENT_AS(bracketpos_backtrack)->stacksize);
+ JUMPHERE(jump);
+ }
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), CURRENT_AS(bracketpos_backtrack)->private_data_ptr, SLJIT_MEM1(STACK_TOP), STACK(-CURRENT_AS(bracketpos_backtrack)->framesize - 1));
+}
+
+static SLJIT_INLINE void compile_braminzero_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+assert_backtrack backtrack;
+
+current->top = NULL;
+current->topbacktracks = NULL;
+current->nextbacktracks = NULL;
+if (current->cc[1] > OP_ASSERTBACK_NOT)
+ {
+ /* Manual call of compile_bracket_matchingpath and compile_bracket_backtrackingpath. */
+ compile_bracket_matchingpath(common, current->cc, current);
+ compile_bracket_backtrackingpath(common, current->top);
+ }
+else
+ {
+ memset(&backtrack, 0, sizeof(backtrack));
+ backtrack.common.cc = current->cc;
+ backtrack.matchingpath = CURRENT_AS(braminzero_backtrack)->matchingpath;
+ /* Manual call of compile_assert_matchingpath. */
+ compile_assert_matchingpath(common, current->cc, &backtrack, FALSE);
+ }
+SLJIT_ASSERT(!current->nextbacktracks && !current->topbacktracks);
+}
+
+static SLJIT_INLINE void compile_control_verb_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+PCRE2_UCHAR opcode = *current->cc;
+struct sljit_label *loop;
+struct sljit_jump *jump;
+
+if (opcode == OP_THEN || opcode == OP_THEN_ARG)
+ {
+ if (common->then_trap != NULL)
+ {
+ SLJIT_ASSERT(common->control_head_ptr != 0);
+
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, type_then_trap);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_IMM, common->then_trap->start);
+ jump = JUMP(SLJIT_JUMP);
+
+ loop = LABEL();
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ JUMPHERE(jump);
+ CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), TMP1, 0, loop);
+ CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(2), TMP2, 0, loop);
+ add_jump(compiler, &common->then_trap->quit, JUMP(SLJIT_JUMP));
+ return;
+ }
+ else if (!common->local_quit_available && common->in_positive_assertion)
+ {
+ add_jump(compiler, &common->positive_assertion_quit, JUMP(SLJIT_JUMP));
+ return;
+ }
+ }
+
+if (common->local_quit_available)
+ {
+ /* Abort match with a fail. */
+ if (common->quit_label == NULL)
+ add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
+ else
+ JUMPTO(SLJIT_JUMP, common->quit_label);
+ return;
+ }
+
+if (opcode == OP_SKIP_ARG)
+ {
+ SLJIT_ASSERT(common->control_head_ptr != 0 && TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
+ OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2));
+ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark));
+
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_R0, 0);
+ add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, SLJIT_R0, 0, SLJIT_IMM, 0));
+ return;
+ }
+
+if (opcode == OP_SKIP)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+else
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_IMM, 0);
+add_jump(compiler, &common->reset_match, JUMP(SLJIT_JUMP));
+}
+
+static SLJIT_INLINE void compile_then_trap_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+struct sljit_jump *jump;
+int size;
+
+if (CURRENT_AS(then_trap_backtrack)->then_trap)
+ {
+ common->then_trap = CURRENT_AS(then_trap_backtrack)->then_trap;
+ return;
+ }
+
+size = CURRENT_AS(then_trap_backtrack)->framesize;
+size = 3 + (size < 0 ? 0 : size);
+
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(size - 3));
+free_stack(common, size);
+jump = JUMP(SLJIT_JUMP);
+
+set_jumps(CURRENT_AS(then_trap_backtrack)->quit, LABEL());
+/* STACK_TOP is set by THEN. */
+if (CURRENT_AS(then_trap_backtrack)->framesize >= 0)
+ {
+ add_jump(compiler, &common->revertframes, JUMP(SLJIT_FAST_CALL));
+ OP2(SLJIT_ADD, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, (CURRENT_AS(then_trap_backtrack)->framesize - 1) * sizeof(sljit_sw));
+ }
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+free_stack(common, 3);
+
+JUMPHERE(jump);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP1, 0);
+}
+
+static void compile_backtrackingpath(compiler_common *common, struct backtrack_common *current)
+{
+DEFINE_COMPILER;
+then_trap_backtrack *save_then_trap = common->then_trap;
+
+while (current)
+ {
+ if (current->nextbacktracks != NULL)
+ set_jumps(current->nextbacktracks, LABEL());
+ switch(*current->cc)
+ {
+ case OP_SET_SOM:
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), TMP1, 0);
+ break;
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ case OP_TYPEPOSUPTO:
+ case OP_CLASS:
+ case OP_NCLASS:
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+#endif
+ compile_iterator_backtrackingpath(common, current);
+ break;
+
+ case OP_REF:
+ case OP_REFI:
+ case OP_DNREF:
+ case OP_DNREFI:
+ compile_ref_iterator_backtrackingpath(common, current);
+ break;
+
+ case OP_RECURSE:
+ compile_recurse_backtrackingpath(common, current);
+ break;
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ compile_assert_backtrackingpath(common, current);
+ break;
+
+ case OP_ONCE:
+ case OP_BRA:
+ case OP_CBRA:
+ case OP_COND:
+ case OP_SBRA:
+ case OP_SCBRA:
+ case OP_SCOND:
+ compile_bracket_backtrackingpath(common, current);
+ break;
+
+ case OP_BRAZERO:
+ if (current->cc[1] > OP_ASSERTBACK_NOT)
+ compile_bracket_backtrackingpath(common, current);
+ else
+ compile_assert_backtrackingpath(common, current);
+ break;
+
+ case OP_BRAPOS:
+ case OP_CBRAPOS:
+ case OP_SBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_BRAPOSZERO:
+ compile_bracketpos_backtrackingpath(common, current);
+ break;
+
+ case OP_BRAMINZERO:
+ compile_braminzero_backtrackingpath(common, current);
+ break;
+
+ case OP_MARK:
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(common->has_skip_arg ? 4 : 0));
+ if (common->has_skip_arg)
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ free_stack(common, common->has_skip_arg ? 5 : 1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, TMP1, 0);
+ if (common->has_skip_arg)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, TMP2, 0);
+ break;
+
+ case OP_THEN:
+ case OP_THEN_ARG:
+ case OP_PRUNE:
+ case OP_PRUNE_ARG:
+ case OP_SKIP:
+ case OP_SKIP_ARG:
+ compile_control_verb_backtrackingpath(common, current);
+ break;
+
+ case OP_COMMIT:
+ case OP_COMMIT_ARG:
+ if (!common->local_quit_available)
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+ if (common->quit_label == NULL)
+ add_jump(compiler, &common->quit, JUMP(SLJIT_JUMP));
+ else
+ JUMPTO(SLJIT_JUMP, common->quit_label);
+ break;
+
+ case OP_CALLOUT:
+ case OP_CALLOUT_STR:
+ case OP_FAIL:
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ set_jumps(current->topbacktracks, LABEL());
+ break;
+
+ case OP_THEN_TRAP:
+ /* A virtual opcode for then traps. */
+ compile_then_trap_backtrackingpath(common, current);
+ break;
+
+ default:
+ SLJIT_UNREACHABLE();
+ break;
+ }
+ current = current->prev;
+ }
+common->then_trap = save_then_trap;
+}
+
+static SLJIT_INLINE void compile_recurse(compiler_common *common)
+{
+DEFINE_COMPILER;
+PCRE2_SPTR cc = common->start + common->currententry->start;
+PCRE2_SPTR ccbegin = cc + 1 + LINK_SIZE + (*cc == OP_BRA ? 0 : IMM2_SIZE);
+PCRE2_SPTR ccend = bracketend(cc) - (1 + LINK_SIZE);
+BOOL needs_control_head;
+BOOL has_quit;
+BOOL has_accept;
+int private_data_size = get_recurse_data_length(common, ccbegin, ccend, &needs_control_head, &has_quit, &has_accept);
+int alt_count, alt_max, local_size;
+backtrack_common altbacktrack;
+jump_list *match = NULL;
+sljit_uw *next_update_addr = NULL;
+struct sljit_jump *alt1 = NULL;
+struct sljit_jump *alt2 = NULL;
+struct sljit_jump *accept_exit = NULL;
+struct sljit_label *quit;
+
+/* Recurse captures then. */
+common->then_trap = NULL;
+
+SLJIT_ASSERT(*cc == OP_BRA || *cc == OP_CBRA || *cc == OP_CBRAPOS || *cc == OP_SCBRA || *cc == OP_SCBRAPOS);
+
+alt_max = no_alternatives(cc);
+alt_count = 0;
+
+/* Matching path. */
+SLJIT_ASSERT(common->currententry->entry_label == NULL && common->recursive_head_ptr != 0);
+common->currententry->entry_label = LABEL();
+set_jumps(common->currententry->entry_calls, common->currententry->entry_label);
+
+sljit_emit_fast_enter(compiler, TMP2, 0);
+count_match(common);
+
+local_size = (alt_max > 1) ? 2 : 1;
+
+/* (Reversed) stack layout:
+ [private data][return address][optional: str ptr] ... [optional: alternative index][recursive_head_ptr] */
+
+allocate_stack(common, private_data_size + local_size);
+/* Save return address. */
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP2, 0);
+
+copy_recurse_data(common, ccbegin, ccend, recurse_copy_from_global, local_size, private_data_size + local_size, has_quit);
+
+/* This variable is saved and restored all time when we enter or exit from a recursive context. */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr, STACK_TOP, 0);
+
+if (needs_control_head)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+
+if (alt_max > 1)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), STR_PTR, 0);
+
+memset(&altbacktrack, 0, sizeof(backtrack_common));
+common->quit_label = NULL;
+common->accept_label = NULL;
+common->quit = NULL;
+common->accept = NULL;
+altbacktrack.cc = ccbegin;
+cc += GET(cc, 1);
+while (1)
+ {
+ altbacktrack.top = NULL;
+ altbacktrack.topbacktracks = NULL;
+
+ if (altbacktrack.cc != ccbegin)
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+
+ compile_matchingpath(common, altbacktrack.cc, cc, &altbacktrack);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return;
+
+ allocate_stack(common, (alt_max > 1 || has_accept) ? 2 : 1);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
+
+ if (alt_max > 1 || has_accept)
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count);
+
+ add_jump(compiler, &match, JUMP(SLJIT_JUMP));
+
+ if (alt_count == 0)
+ {
+ /* Backtracking path entry. */
+ SLJIT_ASSERT(common->currententry->backtrack_label == NULL);
+ common->currententry->backtrack_label = LABEL();
+ set_jumps(common->currententry->backtrack_calls, common->currententry->backtrack_label);
+
+ sljit_emit_fast_enter(compiler, TMP1, 0);
+
+ if (has_accept)
+ accept_exit = CMP(SLJIT_EQUAL, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_max * sizeof (sljit_sw));
+
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(0));
+ /* Save return address. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), STACK(local_size - 1), TMP1, 0);
+
+ copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, has_quit);
+
+ if (alt_max > 1)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(STACK_TOP), STACK(1));
+ free_stack(common, 2);
+
+ if (alt_max > 4)
+ {
+ /* Table jump if alt_max is greater than 4. */
+ next_update_addr = allocate_read_only_data(common, alt_max * sizeof(sljit_uw));
+ if (SLJIT_UNLIKELY(next_update_addr == NULL))
+ return;
+ sljit_emit_ijump(compiler, SLJIT_JUMP, SLJIT_MEM1(TMP1), (sljit_sw)next_update_addr);
+ add_label_addr(common, next_update_addr++);
+ }
+ else
+ {
+ if (alt_max == 4)
+ alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw));
+ alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, sizeof(sljit_uw));
+ }
+ }
+ else
+ free_stack(common, has_accept ? 2 : 1);
+ }
+ else if (alt_max > 4)
+ add_label_addr(common, next_update_addr++);
+ else
+ {
+ if (alt_count != 2 * sizeof(sljit_uw))
+ {
+ JUMPHERE(alt1);
+ if (alt_max == 3 && alt_count == sizeof(sljit_uw))
+ alt2 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 2 * sizeof(sljit_uw));
+ }
+ else
+ {
+ JUMPHERE(alt2);
+ if (alt_max == 4)
+ alt1 = CMP(SLJIT_GREATER_EQUAL, TMP1, 0, SLJIT_IMM, 3 * sizeof(sljit_uw));
+ }
+ }
+
+ alt_count += sizeof(sljit_uw);
+
+ compile_backtrackingpath(common, altbacktrack.top);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ return;
+ set_jumps(altbacktrack.topbacktracks, LABEL());
+
+ if (*cc != OP_ALT)
+ break;
+
+ altbacktrack.cc = cc + 1 + LINK_SIZE;
+ cc += GET(cc, 1);
+ }
+
+/* No alternative is matched. */
+
+quit = LABEL();
+
+copy_recurse_data(common, ccbegin, ccend, recurse_copy_private_to_global, local_size, private_data_size + local_size, has_quit);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1));
+free_stack(common, private_data_size + local_size);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+sljit_emit_fast_return(compiler, TMP2, 0);
+
+if (common->quit != NULL)
+ {
+ SLJIT_ASSERT(has_quit);
+
+ set_jumps(common->quit, LABEL());
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
+ copy_recurse_data(common, ccbegin, ccend, recurse_copy_shared_to_global, local_size, private_data_size + local_size, has_quit);
+ JUMPTO(SLJIT_JUMP, quit);
+ }
+
+if (has_accept)
+ {
+ JUMPHERE(accept_exit);
+ free_stack(common, 2);
+
+ /* Save return address. */
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1), TMP1, 0);
+
+ copy_recurse_data(common, ccbegin, ccend, recurse_copy_kept_shared_to_global, local_size, private_data_size + local_size, has_quit);
+
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(STACK_TOP), STACK(local_size - 1));
+ free_stack(common, private_data_size + local_size);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 0);
+ sljit_emit_fast_return(compiler, TMP2, 0);
+ }
+
+if (common->accept != NULL)
+ {
+ SLJIT_ASSERT(has_accept);
+
+ set_jumps(common->accept, LABEL());
+
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), common->recursive_head_ptr);
+ OP1(SLJIT_MOV, TMP2, 0, STACK_TOP, 0);
+
+ allocate_stack(common, 2);
+ OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(1), SLJIT_IMM, alt_count);
+ }
+
+set_jumps(match, LABEL());
+
+OP1(SLJIT_MOV, SLJIT_MEM1(STACK_TOP), STACK(0), TMP2, 0);
+
+copy_recurse_data(common, ccbegin, ccend, recurse_swap_global, local_size, private_data_size + local_size, has_quit);
+
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), STACK(local_size - 1));
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_IMM, 1);
+sljit_emit_fast_return(compiler, TMP2, 0);
+}
+
+#undef COMPILE_BACKTRACKINGPATH
+#undef CURRENT_AS
+
+static int jit_compile(pcre2_code *code, sljit_u32 mode)
+{
+pcre2_real_code *re = (pcre2_real_code *)code;
+struct sljit_compiler *compiler;
+backtrack_common rootbacktrack;
+compiler_common common_data;
+compiler_common *common = &common_data;
+const sljit_u8 *tables = re->tables;
+void *allocator_data = &re->memctl;
+int private_data_size;
+PCRE2_SPTR ccend;
+executable_functions *functions;
+void *executable_func;
+sljit_uw executable_size;
+sljit_uw total_length;
+label_addr_list *label_addr;
+struct sljit_label *mainloop_label = NULL;
+struct sljit_label *continue_match_label;
+struct sljit_label *empty_match_found_label = NULL;
+struct sljit_label *empty_match_backtrack_label = NULL;
+struct sljit_label *reset_match_label;
+struct sljit_label *quit_label;
+struct sljit_jump *jump;
+struct sljit_jump *minlength_check_failed = NULL;
+struct sljit_jump *reqbyte_notfound = NULL;
+struct sljit_jump *empty_match = NULL;
+struct sljit_jump *end_anchor_failed = NULL;
+
+SLJIT_ASSERT(tables);
+
+memset(&rootbacktrack, 0, sizeof(backtrack_common));
+memset(common, 0, sizeof(compiler_common));
+common->re = re;
+common->name_table = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code));
+rootbacktrack.cc = common->name_table + re->name_count * re->name_entry_size;
+
+common->start = rootbacktrack.cc;
+common->read_only_data_head = NULL;
+common->fcc = tables + fcc_offset;
+common->lcc = (sljit_sw)(tables + lcc_offset);
+common->mode = mode;
+common->might_be_empty = re->minlength == 0;
+common->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+ {
+ case PCRE2_NEWLINE_CR: common->newline = CHAR_CR; break;
+ case PCRE2_NEWLINE_LF: common->newline = CHAR_NL; break;
+ case PCRE2_NEWLINE_CRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; break;
+ case PCRE2_NEWLINE_ANY: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANY; break;
+ case PCRE2_NEWLINE_ANYCRLF: common->newline = (CHAR_CR << 8) | CHAR_NL; common->nltype = NLTYPE_ANYCRLF; break;
+ default: return PCRE2_ERROR_INTERNAL;
+ }
+common->nlmax = READ_CHAR_MAX;
+common->nlmin = 0;
+if (re->bsr_convention == PCRE2_BSR_UNICODE)
+ common->bsr_nltype = NLTYPE_ANY;
+else if (re->bsr_convention == PCRE2_BSR_ANYCRLF)
+ common->bsr_nltype = NLTYPE_ANYCRLF;
+else
+ {
+#ifdef BSR_ANYCRLF
+ common->bsr_nltype = NLTYPE_ANYCRLF;
+#else
+ common->bsr_nltype = NLTYPE_ANY;
+#endif
+ }
+common->bsr_nlmax = READ_CHAR_MAX;
+common->bsr_nlmin = 0;
+common->endonly = (re->overall_options & PCRE2_DOLLAR_ENDONLY) != 0;
+common->ctypes = (sljit_sw)(tables + ctypes_offset);
+common->name_count = re->name_count;
+common->name_entry_size = re->name_entry_size;
+common->unset_backref = (re->overall_options & PCRE2_MATCH_UNSET_BACKREF) != 0;
+common->alt_circumflex = (re->overall_options & PCRE2_ALT_CIRCUMFLEX) != 0;
+#ifdef SUPPORT_UNICODE
+/* PCRE_UTF[16|32] have the same value as PCRE_UTF8. */
+common->utf = (re->overall_options & PCRE2_UTF) != 0;
+common->use_ucp = (re->overall_options & PCRE2_UCP) != 0;
+if (common->utf)
+ {
+ if (common->nltype == NLTYPE_ANY)
+ common->nlmax = 0x2029;
+ else if (common->nltype == NLTYPE_ANYCRLF)
+ common->nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL;
+ else
+ {
+ /* We only care about the first newline character. */
+ common->nlmax = common->newline & 0xff;
+ }
+
+ if (common->nltype == NLTYPE_FIXED)
+ common->nlmin = common->newline & 0xff;
+ else
+ common->nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL;
+
+ if (common->bsr_nltype == NLTYPE_ANY)
+ common->bsr_nlmax = 0x2029;
+ else
+ common->bsr_nlmax = (CHAR_CR > CHAR_NL) ? CHAR_CR : CHAR_NL;
+ common->bsr_nlmin = (CHAR_CR < CHAR_NL) ? CHAR_CR : CHAR_NL;
+ }
+#endif /* SUPPORT_UNICODE */
+ccend = bracketend(common->start);
+
+/* Calculate the local space size on the stack. */
+common->ovector_start = LIMIT_MATCH + sizeof(sljit_sw);
+common->optimized_cbracket = (sljit_u8 *)SLJIT_MALLOC(re->top_bracket + 1, allocator_data);
+if (!common->optimized_cbracket)
+ return PCRE2_ERROR_NOMEMORY;
+#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 1
+memset(common->optimized_cbracket, 0, re->top_bracket + 1);
+#else
+memset(common->optimized_cbracket, 1, re->top_bracket + 1);
+#endif
+
+SLJIT_ASSERT(*common->start == OP_BRA && ccend[-(1 + LINK_SIZE)] == OP_KET);
+#if defined DEBUG_FORCE_UNOPTIMIZED_CBRAS && DEBUG_FORCE_UNOPTIMIZED_CBRAS == 2
+common->capture_last_ptr = common->ovector_start;
+common->ovector_start += sizeof(sljit_sw);
+#endif
+if (!check_opcode_types(common, common->start, ccend))
+ {
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+/* Checking flags and updating ovector_start. */
+if (mode == PCRE2_JIT_COMPLETE && (re->flags & PCRE2_LASTSET) != 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+ {
+ common->req_char_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+if (mode != PCRE2_JIT_COMPLETE)
+ {
+ common->start_used_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ if (mode == PCRE2_JIT_PARTIAL_SOFT)
+ {
+ common->hit_start = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+ }
+if ((re->overall_options & (PCRE2_FIRSTLINE | PCRE2_USE_OFFSET_LIMIT)) != 0)
+ {
+ common->match_end_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+#if defined DEBUG_FORCE_CONTROL_HEAD && DEBUG_FORCE_CONTROL_HEAD
+common->control_head_ptr = 1;
+#endif
+if (common->control_head_ptr != 0)
+ {
+ common->control_head_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+if (common->has_set_som)
+ {
+ /* Saving the real start pointer is necessary. */
+ common->start_ptr = common->ovector_start;
+ common->ovector_start += sizeof(sljit_sw);
+ }
+
+/* Aligning ovector to even number of sljit words. */
+if ((common->ovector_start & sizeof(sljit_sw)) != 0)
+ common->ovector_start += sizeof(sljit_sw);
+
+if (common->start_ptr == 0)
+ common->start_ptr = OVECTOR(0);
+
+/* Capturing brackets cannot be optimized if callouts are allowed. */
+if (common->capture_last_ptr != 0)
+ memset(common->optimized_cbracket, 0, re->top_bracket + 1);
+
+SLJIT_ASSERT(!(common->req_char_ptr != 0 && common->start_used_ptr != 0));
+common->cbra_ptr = OVECTOR_START + (re->top_bracket + 1) * 2 * sizeof(sljit_sw);
+
+total_length = ccend - common->start;
+common->private_data_ptrs = (sljit_s32 *)SLJIT_MALLOC(total_length * (sizeof(sljit_s32) + (common->has_then ? 1 : 0)), allocator_data);
+if (!common->private_data_ptrs)
+ {
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+memset(common->private_data_ptrs, 0, total_length * sizeof(sljit_s32));
+
+private_data_size = common->cbra_ptr + (re->top_bracket + 1) * sizeof(sljit_sw);
+set_private_data_ptrs(common, &private_data_size, ccend);
+if ((re->overall_options & PCRE2_ANCHORED) == 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+ {
+ if (!detect_fast_forward_skip(common, &private_data_size) && !common->has_skip_in_assert_back)
+ detect_fast_fail(common, common->start, &private_data_size, 4);
+ }
+
+SLJIT_ASSERT(common->fast_fail_start_ptr <= common->fast_fail_end_ptr);
+
+if (private_data_size > SLJIT_MAX_LOCAL_SIZE)
+ {
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+if (common->has_then)
+ {
+ common->then_offsets = (sljit_u8 *)(common->private_data_ptrs + total_length);
+ memset(common->then_offsets, 0, total_length);
+ set_then_offsets(common, common->start, NULL);
+ }
+
+compiler = sljit_create_compiler(allocator_data);
+if (!compiler)
+ {
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+common->compiler = compiler;
+
+/* Main pcre_jit_exec entry. */
+sljit_emit_enter(compiler, 0, SLJIT_ARG1(SW), 5, 5, 0, 0, private_data_size);
+
+/* Register init. */
+reset_ovector(common, (re->top_bracket + 1) * 2);
+if (common->req_char_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->req_char_ptr, SLJIT_R0, 0);
+
+OP1(SLJIT_MOV, ARGUMENTS, 0, SLJIT_S0, 0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_S0, 0);
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end));
+OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
+OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match));
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, end));
+OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, start));
+OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0);
+
+if (common->fast_fail_start_ptr < common->fast_fail_end_ptr)
+ reset_fast_fail(common);
+
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
+if (common->mark_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->mark_ptr, SLJIT_IMM, 0);
+if (common->control_head_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
+
+/* Main part of the matching */
+if ((re->overall_options & PCRE2_ANCHORED) == 0)
+ {
+ mainloop_label = mainloop_entry(common);
+ continue_match_label = LABEL();
+ /* Forward search if possible. */
+ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+ {
+ if (mode == PCRE2_JIT_COMPLETE && fast_forward_first_n_chars(common))
+ ;
+ else if ((re->flags & PCRE2_FIRSTSET) != 0)
+ fast_forward_first_char(common);
+ else if ((re->flags & PCRE2_STARTLINE) != 0)
+ fast_forward_newline(common);
+ else if ((re->flags & PCRE2_FIRSTMAPSET) != 0)
+ fast_forward_start_bits(common);
+ }
+ }
+else
+ continue_match_label = LABEL();
+
+if (mode == PCRE2_JIT_COMPLETE && re->minlength > 0 && (re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+ {
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+ OP2(SLJIT_ADD, TMP2, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(re->minlength));
+ minlength_check_failed = CMP(SLJIT_GREATER, TMP2, 0, STR_END, 0);
+ }
+if (common->req_char_ptr != 0)
+ reqbyte_notfound = search_requested_char(common, (PCRE2_UCHAR)(re->last_codeunit), (re->flags & PCRE2_LASTCASELESS) != 0, (re->flags & PCRE2_FIRSTSET) != 0);
+
+/* Store the current STR_PTR in OVECTOR(0). */
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), OVECTOR(0), STR_PTR, 0);
+/* Copy the limit of allowed recursions. */
+OP1(SLJIT_MOV, COUNT_MATCH, 0, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH);
+if (common->capture_last_ptr != 0)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->capture_last_ptr, SLJIT_IMM, 0);
+if (common->fast_forward_bc_ptr != NULL)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), PRIVATE_DATA(common->fast_forward_bc_ptr + 1), STR_PTR, 0);
+
+if (common->start_ptr != OVECTOR(0))
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_ptr, STR_PTR, 0);
+
+/* Copy the beginning of the string. */
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+ {
+ jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+ JUMPHERE(jump);
+ }
+else if (mode == PCRE2_JIT_PARTIAL_HARD)
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, STR_PTR, 0);
+
+compile_matchingpath(common, common->start, ccend, &rootbacktrack);
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ {
+ sljit_free_compiler(compiler);
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+if ((re->overall_options & PCRE2_ENDANCHORED) != 0)
+ end_anchor_failed = CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, STR_END, 0);
+
+if (common->might_be_empty)
+ {
+ empty_match = CMP(SLJIT_EQUAL, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(0));
+ empty_match_found_label = LABEL();
+ }
+
+common->accept_label = LABEL();
+if (common->accept != NULL)
+ set_jumps(common->accept, common->accept_label);
+
+/* This means we have a match. Update the ovector. */
+copy_ovector(common, re->top_bracket + 1);
+common->quit_label = common->abort_label = LABEL();
+if (common->quit != NULL)
+ set_jumps(common->quit, common->quit_label);
+if (common->abort != NULL)
+ set_jumps(common->abort, common->abort_label);
+if (minlength_check_failed != NULL)
+ SET_LABEL(minlength_check_failed, common->abort_label);
+sljit_emit_return(compiler, SLJIT_MOV, SLJIT_RETURN_REG, 0);
+
+if (common->failed_match != NULL)
+ {
+ SLJIT_ASSERT(common->mode == PCRE2_JIT_COMPLETE);
+ set_jumps(common->failed_match, LABEL());
+ OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+ JUMPTO(SLJIT_JUMP, common->abort_label);
+ }
+
+if ((re->overall_options & PCRE2_ENDANCHORED) != 0)
+ JUMPHERE(end_anchor_failed);
+
+if (mode != PCRE2_JIT_COMPLETE)
+ {
+ common->partialmatchlabel = LABEL();
+ set_jumps(common->partialmatch, common->partialmatchlabel);
+ return_with_partial_match(common, common->quit_label);
+ }
+
+if (common->might_be_empty)
+ empty_match_backtrack_label = LABEL();
+compile_backtrackingpath(common, rootbacktrack.top);
+if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ {
+ sljit_free_compiler(compiler);
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+SLJIT_ASSERT(rootbacktrack.prev == NULL);
+reset_match_label = LABEL();
+
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+ {
+ /* Update hit_start only in the first time. */
+ jump = CMP(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, 0);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->start_used_ptr, SLJIT_IMM, -1);
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->hit_start, TMP1, 0);
+ JUMPHERE(jump);
+ }
+
+/* Check we have remaining characters. */
+if ((re->overall_options & PCRE2_ANCHORED) == 0 && common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->match_end_ptr);
+ }
+
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP),
+ (common->fast_forward_bc_ptr != NULL) ? (PRIVATE_DATA(common->fast_forward_bc_ptr + 1)) : common->start_ptr);
+
+if ((re->overall_options & PCRE2_ANCHORED) == 0)
+ {
+ if (common->ff_newline_shortcut != NULL)
+ {
+ /* There cannot be more newlines if PCRE2_FIRSTLINE is set. */
+ if ((re->overall_options & PCRE2_FIRSTLINE) == 0)
+ {
+ if (common->match_end_ptr != 0)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, STR_END, 0);
+ OP1(SLJIT_MOV, STR_END, 0, TMP1, 0);
+ CMPTO(SLJIT_LESS, STR_PTR, 0, TMP1, 0, common->ff_newline_shortcut);
+ OP1(SLJIT_MOV, STR_END, 0, TMP3, 0);
+ }
+ else
+ CMPTO(SLJIT_LESS, STR_PTR, 0, STR_END, 0, common->ff_newline_shortcut);
+ }
+ }
+ else
+ CMPTO(SLJIT_LESS, STR_PTR, 0, (common->match_end_ptr == 0) ? STR_END : TMP1, 0, mainloop_label);
+ }
+
+/* No more remaining characters. */
+if (reqbyte_notfound != NULL)
+ JUMPHERE(reqbyte_notfound);
+
+if (mode == PCRE2_JIT_PARTIAL_SOFT)
+ CMPTO(SLJIT_NOT_EQUAL, SLJIT_MEM1(SLJIT_SP), common->hit_start, SLJIT_IMM, -1, common->partialmatchlabel);
+
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_NOMATCH);
+JUMPTO(SLJIT_JUMP, common->quit_label);
+
+flush_stubs(common);
+
+if (common->might_be_empty)
+ {
+ JUMPHERE(empty_match);
+ OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
+ OP1(SLJIT_MOV_U32, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, options));
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY);
+ JUMPTO(SLJIT_NOT_ZERO, empty_match_backtrack_label);
+ OP2(SLJIT_AND | SLJIT_SET_Z, SLJIT_UNUSED, 0, TMP2, 0, SLJIT_IMM, PCRE2_NOTEMPTY_ATSTART);
+ JUMPTO(SLJIT_ZERO, empty_match_found_label);
+ OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str));
+ CMPTO(SLJIT_NOT_EQUAL, TMP2, 0, STR_PTR, 0, empty_match_found_label);
+ JUMPTO(SLJIT_JUMP, empty_match_backtrack_label);
+ }
+
+common->fast_forward_bc_ptr = NULL;
+common->fast_fail_start_ptr = 0;
+common->fast_fail_end_ptr = 0;
+common->currententry = common->entries;
+common->local_quit_available = TRUE;
+quit_label = common->quit_label;
+while (common->currententry != NULL)
+ {
+ /* Might add new entries. */
+ compile_recurse(common);
+ if (SLJIT_UNLIKELY(sljit_get_compiler_error(compiler)))
+ {
+ sljit_free_compiler(compiler);
+ SLJIT_FREE(common->optimized_cbracket, allocator_data);
+ SLJIT_FREE(common->private_data_ptrs, allocator_data);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+ flush_stubs(common);
+ common->currententry = common->currententry->next;
+ }
+common->local_quit_available = FALSE;
+common->quit_label = quit_label;
+
+/* Allocating stack, returns with PCRE_ERROR_JIT_STACKLIMIT if fails. */
+/* This is a (really) rare case. */
+set_jumps(common->stackalloc, LABEL());
+/* RETURN_ADDR is not a saved register. */
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+SLJIT_ASSERT(TMP1 == SLJIT_R0 && STR_PTR == SLJIT_R1);
+
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STR_PTR, 0);
+OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE);
+OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack));
+OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0);
+
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
+
+jump = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+OP1(SLJIT_MOV, TMP2, 0, STACK_LIMIT, 0);
+OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_RETURN_REG, 0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+sljit_emit_fast_return(compiler, TMP1, 0);
+
+/* Allocation failed. */
+JUMPHERE(jump);
+/* We break the return address cache here, but this is a really rare case. */
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_JIT_STACKLIMIT);
+JUMPTO(SLJIT_JUMP, common->quit_label);
+
+/* Call limit reached. */
+set_jumps(common->calllimit, LABEL());
+OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_IMM, PCRE2_ERROR_MATCHLIMIT);
+JUMPTO(SLJIT_JUMP, common->quit_label);
+
+if (common->revertframes != NULL)
+ {
+ set_jumps(common->revertframes, LABEL());
+ do_revertframes(common);
+ }
+if (common->wordboundary != NULL)
+ {
+ set_jumps(common->wordboundary, LABEL());
+ check_wordboundary(common);
+ }
+if (common->anynewline != NULL)
+ {
+ set_jumps(common->anynewline, LABEL());
+ check_anynewline(common);
+ }
+if (common->hspace != NULL)
+ {
+ set_jumps(common->hspace, LABEL());
+ check_hspace(common);
+ }
+if (common->vspace != NULL)
+ {
+ set_jumps(common->vspace, LABEL());
+ check_vspace(common);
+ }
+if (common->casefulcmp != NULL)
+ {
+ set_jumps(common->casefulcmp, LABEL());
+ do_casefulcmp(common);
+ }
+if (common->caselesscmp != NULL)
+ {
+ set_jumps(common->caselesscmp, LABEL());
+ do_caselesscmp(common);
+ }
+if (common->reset_match != NULL)
+ {
+ set_jumps(common->reset_match, LABEL());
+ do_reset_match(common, (re->top_bracket + 1) * 2);
+ CMPTO(SLJIT_GREATER, STR_PTR, 0, TMP1, 0, continue_match_label);
+ OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0);
+ JUMPTO(SLJIT_JUMP, reset_match_label);
+ }
+#ifdef SUPPORT_UNICODE
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if (common->utfreadchar != NULL)
+ {
+ set_jumps(common->utfreadchar, LABEL());
+ do_utfreadchar(common);
+ }
+if (common->utfreadchar16 != NULL)
+ {
+ set_jumps(common->utfreadchar16, LABEL());
+ do_utfreadchar16(common);
+ }
+if (common->utfreadtype8 != NULL)
+ {
+ set_jumps(common->utfreadtype8, LABEL());
+ do_utfreadtype8(common);
+ }
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+if (common->getucd != NULL)
+ {
+ set_jumps(common->getucd, LABEL());
+ do_getucd(common);
+ }
+#endif /* SUPPORT_UNICODE */
+
+SLJIT_FREE(common->optimized_cbracket, allocator_data);
+SLJIT_FREE(common->private_data_ptrs, allocator_data);
+
+executable_func = sljit_generate_code(compiler);
+executable_size = sljit_get_generated_code_size(compiler);
+label_addr = common->label_addrs;
+while (label_addr != NULL)
+ {
+ *label_addr->update_addr = sljit_get_label_addr(label_addr->label);
+ label_addr = label_addr->next;
+ }
+sljit_free_compiler(compiler);
+if (executable_func == NULL)
+ {
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+/* Reuse the function descriptor if possible. */
+if (re->executable_jit != NULL)
+ functions = (executable_functions *)re->executable_jit;
+else
+ {
+ functions = SLJIT_MALLOC(sizeof(executable_functions), allocator_data);
+ if (functions == NULL)
+ {
+ /* This case is highly unlikely since we just recently
+ freed a lot of memory. Not impossible though. */
+ sljit_free_code(executable_func);
+ PRIV(jit_free_rodata)(common->read_only_data_head, compiler->allocator_data);
+ return PCRE2_ERROR_NOMEMORY;
+ }
+ memset(functions, 0, sizeof(executable_functions));
+ functions->top_bracket = re->top_bracket + 1;
+ functions->limit_match = re->limit_match;
+ re->executable_jit = functions;
+ }
+
+/* Turn mode into an index. */
+if (mode == PCRE2_JIT_COMPLETE)
+ mode = 0;
+else
+ mode = (mode == PCRE2_JIT_PARTIAL_SOFT) ? 1 : 2;
+
+SLJIT_ASSERT(mode < JIT_NUMBER_OF_COMPILE_MODES);
+functions->executable_funcs[mode] = executable_func;
+functions->read_only_data_heads[mode] = common->read_only_data_head;
+functions->executable_sizes[mode] = executable_size;
+return 0;
+}
+
+#endif
+
+/*************************************************
+* JIT compile a Regular Expression *
+*************************************************/
+
+/* This function used JIT to convert a previously-compiled pattern into machine
+code.
+
+Arguments:
+ code a compiled pattern
+ options JIT option bits
+
+Returns: 0: success or (*NOJIT) was used
+ <0: an error code
+*/
+
+#define PUBLIC_JIT_COMPILE_OPTIONS \
+ (PCRE2_JIT_COMPLETE|PCRE2_JIT_PARTIAL_SOFT|PCRE2_JIT_PARTIAL_HARD)
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_jit_compile(pcre2_code *code, uint32_t options)
+{
+#ifndef SUPPORT_JIT
+
+(void)code;
+(void)options;
+return PCRE2_ERROR_JIT_BADOPTION;
+
+#else /* SUPPORT_JIT */
+
+pcre2_real_code *re = (pcre2_real_code *)code;
+executable_functions *functions;
+int result;
+
+if (code == NULL)
+ return PCRE2_ERROR_NULL;
+
+if ((options & ~PUBLIC_JIT_COMPILE_OPTIONS) != 0)
+ return PCRE2_ERROR_JIT_BADOPTION;
+
+if ((re->flags & PCRE2_NOJIT) != 0) return 0;
+
+functions = (executable_functions *)re->executable_jit;
+
+if ((options & PCRE2_JIT_COMPLETE) != 0 && (functions == NULL
+ || functions->executable_funcs[0] == NULL)) {
+ result = jit_compile(code, PCRE2_JIT_COMPLETE);
+ if (result != 0)
+ return result;
+ }
+
+if ((options & PCRE2_JIT_PARTIAL_SOFT) != 0 && (functions == NULL
+ || functions->executable_funcs[1] == NULL)) {
+ result = jit_compile(code, PCRE2_JIT_PARTIAL_SOFT);
+ if (result != 0)
+ return result;
+ }
+
+if ((options & PCRE2_JIT_PARTIAL_HARD) != 0 && (functions == NULL
+ || functions->executable_funcs[2] == NULL)) {
+ result = jit_compile(code, PCRE2_JIT_PARTIAL_HARD);
+ if (result != 0)
+ return result;
+ }
+
+return 0;
+
+#endif /* SUPPORT_JIT */
+}
+
+/* JIT compiler uses an all-in-one approach. This improves security,
+ since the code generator functions are not exported. */
+
+#define INCLUDED_FROM_PCRE2_JIT_COMPILE
+
+#include "pcre2_jit_match.c"
+#include "pcre2_jit_misc.c"
+
+/* End of pcre2_jit_compile.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_jit_match.c b/test/monniaux/pcre2-10.32/pcre2_jit_match.c
new file mode 100644
index 00000000..5a66545b
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_jit_match.c
@@ -0,0 +1,189 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE
+#error This file must be included from pcre2_jit_compile.c.
+#endif
+
+#ifdef SUPPORT_JIT
+
+static SLJIT_NOINLINE int jit_machine_stack_exec(jit_arguments *arguments, jit_function executable_func)
+{
+sljit_u8 local_space[MACHINE_STACK_SIZE];
+struct sljit_stack local_stack;
+
+local_stack.min_start = local_space;
+local_stack.start = local_space;
+local_stack.end = local_space + MACHINE_STACK_SIZE;
+local_stack.top = local_space + MACHINE_STACK_SIZE;
+arguments->stack = &local_stack;
+return executable_func(arguments);
+}
+
+#endif
+
+
+/*************************************************
+* Do a JIT pattern match *
+*************************************************/
+
+/* This function runs a JIT pattern match.
+
+Arguments:
+ code points to the compiled expression
+ subject points to the subject string
+ length length of subject string (may contain binary zeros)
+ start_offset where to start in the subject string
+ options option bits
+ match_data points to a match_data block
+ mcontext points to a match context
+ jit_stack points to a JIT stack
+
+Returns: > 0 => success; value is the number of ovector pairs filled
+ = 0 => success, but ovector is not big enough
+ -1 => failed to match (PCRE_ERROR_NOMATCH)
+ < -1 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_jit_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext)
+{
+#ifndef SUPPORT_JIT
+
+(void)code;
+(void)subject;
+(void)length;
+(void)start_offset;
+(void)options;
+(void)match_data;
+(void)mcontext;
+return PCRE2_ERROR_JIT_BADOPTION;
+
+#else /* SUPPORT_JIT */
+
+pcre2_real_code *re = (pcre2_real_code *)code;
+executable_functions *functions = (executable_functions *)re->executable_jit;
+pcre2_jit_stack *jit_stack;
+uint32_t oveccount = match_data->oveccount;
+uint32_t max_oveccount;
+union {
+ void *executable_func;
+ jit_function call_executable_func;
+} convert_executable_func;
+jit_arguments arguments;
+int rc;
+int index = 0;
+
+if ((options & PCRE2_PARTIAL_HARD) != 0)
+ index = 2;
+else if ((options & PCRE2_PARTIAL_SOFT) != 0)
+ index = 1;
+
+if (functions == NULL || functions->executable_funcs[index] == NULL)
+ return PCRE2_ERROR_JIT_BADOPTION;
+
+/* Sanity checks should be handled by pcre_exec. */
+arguments.str = subject + start_offset;
+arguments.begin = subject;
+arguments.end = subject + length;
+arguments.match_data = match_data;
+arguments.startchar_ptr = subject;
+arguments.mark_ptr = NULL;
+arguments.options = options;
+
+if (mcontext != NULL)
+ {
+ arguments.callout = mcontext->callout;
+ arguments.callout_data = mcontext->callout_data;
+ arguments.offset_limit = mcontext->offset_limit;
+ arguments.limit_match = (mcontext->match_limit < re->limit_match)?
+ mcontext->match_limit : re->limit_match;
+ if (mcontext->jit_callback != NULL)
+ jit_stack = mcontext->jit_callback(mcontext->jit_callback_data);
+ else
+ jit_stack = (pcre2_jit_stack *)mcontext->jit_callback_data;
+ }
+else
+ {
+ arguments.callout = NULL;
+ arguments.callout_data = NULL;
+ arguments.offset_limit = PCRE2_UNSET;
+ arguments.limit_match = (MATCH_LIMIT < re->limit_match)?
+ MATCH_LIMIT : re->limit_match;
+ jit_stack = NULL;
+ }
+
+/* JIT only need two offsets for each ovector entry. Hence
+ the last 1/3 of the ovector will never be touched. */
+
+max_oveccount = functions->top_bracket;
+if (oveccount > max_oveccount)
+ oveccount = max_oveccount;
+arguments.oveccount = oveccount << 1;
+
+
+convert_executable_func.executable_func = functions->executable_funcs[index];
+if (jit_stack != NULL)
+ {
+ arguments.stack = (struct sljit_stack *)(jit_stack->stack);
+ rc = convert_executable_func.call_executable_func(&arguments);
+ }
+else
+ rc = jit_machine_stack_exec(&arguments, convert_executable_func.call_executable_func);
+
+if (rc > (int)oveccount)
+ rc = 0;
+match_data->code = re;
+match_data->subject = subject;
+match_data->rc = rc;
+match_data->startchar = arguments.startchar_ptr - subject;
+match_data->leftchar = 0;
+match_data->rightchar = 0;
+match_data->mark = arguments.mark_ptr;
+match_data->matchedby = PCRE2_MATCHEDBY_JIT;
+
+return match_data->rc;
+
+#endif /* SUPPORT_JIT */
+}
+
+/* End of pcre2_jit_match.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_jit_misc.c b/test/monniaux/pcre2-10.32/pcre2_jit_misc.c
new file mode 100644
index 00000000..efdb0558
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_jit_misc.c
@@ -0,0 +1,227 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifndef INCLUDED_FROM_PCRE2_JIT_COMPILE
+#error This file must be included from pcre2_jit_compile.c.
+#endif
+
+
+
+/*************************************************
+* Free JIT read-only data *
+*************************************************/
+
+void
+PRIV(jit_free_rodata)(void *current, void *allocator_data)
+{
+#ifndef SUPPORT_JIT
+(void)current;
+(void)allocator_data;
+#else /* SUPPORT_JIT */
+void *next;
+
+SLJIT_UNUSED_ARG(allocator_data);
+
+while (current != NULL)
+ {
+ next = *(void**)current;
+ SLJIT_FREE(current, allocator_data);
+ current = next;
+ }
+
+#endif /* SUPPORT_JIT */
+}
+
+/*************************************************
+* Free JIT compiled code *
+*************************************************/
+
+void
+PRIV(jit_free)(void *executable_jit, pcre2_memctl *memctl)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+(void)memctl;
+#else /* SUPPORT_JIT */
+
+executable_functions *functions = (executable_functions *)executable_jit;
+void *allocator_data = memctl;
+int i;
+
+for (i = 0; i < JIT_NUMBER_OF_COMPILE_MODES; i++)
+ {
+ if (functions->executable_funcs[i] != NULL)
+ sljit_free_code(functions->executable_funcs[i]);
+ PRIV(jit_free_rodata)(functions->read_only_data_heads[i], allocator_data);
+ }
+
+SLJIT_FREE(functions, allocator_data);
+
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Free unused JIT memory *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_free_unused_memory(pcre2_general_context *gcontext)
+{
+#ifndef SUPPORT_JIT
+(void)gcontext; /* Suppress warning */
+#else /* SUPPORT_JIT */
+SLJIT_UNUSED_ARG(gcontext);
+sljit_free_unused_memory_exec();
+#endif /* SUPPORT_JIT */
+}
+
+
+
+/*************************************************
+* Allocate a JIT stack *
+*************************************************/
+
+PCRE2_EXP_DEFN pcre2_jit_stack * PCRE2_CALL_CONVENTION
+pcre2_jit_stack_create(size_t startsize, size_t maxsize,
+ pcre2_general_context *gcontext)
+{
+#ifndef SUPPORT_JIT
+
+(void)gcontext;
+(void)startsize;
+(void)maxsize;
+return NULL;
+
+#else /* SUPPORT_JIT */
+
+pcre2_jit_stack *jit_stack;
+
+if (startsize < 1 || maxsize < 1)
+ return NULL;
+if (startsize > maxsize)
+ startsize = maxsize;
+startsize = (startsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+maxsize = (maxsize + STACK_GROWTH_RATE - 1) & ~(STACK_GROWTH_RATE - 1);
+
+jit_stack = PRIV(memctl_malloc)(sizeof(pcre2_real_jit_stack), (pcre2_memctl *)gcontext);
+if (jit_stack == NULL) return NULL;
+jit_stack->stack = sljit_allocate_stack(startsize, maxsize, &jit_stack->memctl);
+return jit_stack;
+
+#endif
+}
+
+
+/*************************************************
+* Assign a JIT stack to a pattern *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_stack_assign(pcre2_match_context *mcontext, pcre2_jit_callback callback,
+ void *callback_data)
+{
+#ifndef SUPPORT_JIT
+(void)mcontext;
+(void)callback;
+(void)callback_data;
+#else /* SUPPORT_JIT */
+
+if (mcontext == NULL) return;
+mcontext->jit_callback = callback;
+mcontext->jit_callback_data = callback_data;
+
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Free a JIT stack *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_jit_stack_free(pcre2_jit_stack *jit_stack)
+{
+#ifndef SUPPORT_JIT
+(void)jit_stack;
+#else /* SUPPORT_JIT */
+if (jit_stack != NULL)
+ {
+ sljit_free_stack((struct sljit_stack *)(jit_stack->stack), &jit_stack->memctl);
+ jit_stack->memctl.free(jit_stack, jit_stack->memctl.memory_data);
+ }
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Get target CPU type *
+*************************************************/
+
+const char*
+PRIV(jit_get_target)(void)
+{
+#ifndef SUPPORT_JIT
+return "JIT is not supported";
+#else /* SUPPORT_JIT */
+return sljit_get_platform_name();
+#endif /* SUPPORT_JIT */
+}
+
+
+/*************************************************
+* Get size of JIT code *
+*************************************************/
+
+size_t
+PRIV(jit_get_size)(void *executable_jit)
+{
+#ifndef SUPPORT_JIT
+(void)executable_jit;
+return 0;
+#else /* SUPPORT_JIT */
+sljit_uw *executable_sizes = ((executable_functions *)executable_jit)->executable_sizes;
+SLJIT_COMPILE_ASSERT(JIT_NUMBER_OF_COMPILE_MODES == 3, number_of_compile_modes_changed);
+return executable_sizes[0] + executable_sizes[1] + executable_sizes[2];
+#endif
+}
+
+/* End of pcre2_jit_misc.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_maketables.c b/test/monniaux/pcre2-10.32/pcre2_maketables.c
new file mode 100644
index 00000000..537edba8
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_maketables.c
@@ -0,0 +1,150 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains the external function pcre2_maketables(), which builds
+character tables for PCRE2 in the current locale. The file is compiled on its
+own as part of the PCRE2 library. However, it is also included in the
+compilation of dftables.c, in which case the macro DFTABLES is defined. */
+
+#ifndef DFTABLES
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
+# include "pcre2_internal.h"
+#endif
+
+
+
+/*************************************************
+* Create PCRE2 character tables *
+*************************************************/
+
+/* This function builds a set of character tables for use by PCRE2 and returns
+a pointer to them. They are build using the ctype functions, and consequently
+their contents will depend upon the current locale setting. When compiled as
+part of the library, the store is obtained via a general context malloc, if
+supplied, but when DFTABLES is defined (when compiling the dftables auxiliary
+program) malloc() is used, and the function has a different name so as not to
+clash with the prototype in pcre2.h.
+
+Arguments: none when DFTABLES is defined
+ else a PCRE2 general context or NULL
+Returns: pointer to the contiguous block of data
+*/
+
+#ifdef DFTABLES /* Included in freestanding dftables.c program */
+static const uint8_t *maketables(void)
+{
+uint8_t *yield = (uint8_t *)malloc(tables_length);
+
+#else /* Not DFTABLES, compiling the library */
+PCRE2_EXP_DEFN const uint8_t * PCRE2_CALL_CONVENTION
+pcre2_maketables(pcre2_general_context *gcontext)
+{
+uint8_t *yield = (uint8_t *)((gcontext != NULL)?
+ gcontext->memctl.malloc(tables_length, gcontext->memctl.memory_data) :
+ malloc(tables_length));
+#endif /* DFTABLES */
+
+int i;
+uint8_t *p;
+
+if (yield == NULL) return NULL;
+p = yield;
+
+/* First comes the lower casing table */
+
+for (i = 0; i < 256; i++) *p++ = tolower(i);
+
+/* Next the case-flipping table */
+
+for (i = 0; i < 256; i++) *p++ = islower(i)? toupper(i) : tolower(i);
+
+/* Then the character class tables. Don't try to be clever and save effort on
+exclusive ones - in some locales things may be different.
+
+Note that the table for "space" includes everything "isspace" gives, including
+VT in the default locale. This makes it work for the POSIX class [:space:].
+From release 8.34 is is also correct for Perl space, because Perl added VT at
+release 5.18.
+
+Note also that it is possible for a character to be alnum or alpha without
+being lower or upper, such as "male and female ordinals" (\xAA and \xBA) in the
+fr_FR locale (at least under Debian Linux's locales as of 12/2005). So we must
+test for alnum specially. */
+
+memset(p, 0, cbit_length);
+for (i = 0; i < 256; i++)
+ {
+ if (isdigit(i)) p[cbit_digit + i/8] |= 1 << (i&7);
+ if (isupper(i)) p[cbit_upper + i/8] |= 1 << (i&7);
+ if (islower(i)) p[cbit_lower + i/8] |= 1 << (i&7);
+ if (isalnum(i)) p[cbit_word + i/8] |= 1 << (i&7);
+ if (i == '_') p[cbit_word + i/8] |= 1 << (i&7);
+ if (isspace(i)) p[cbit_space + i/8] |= 1 << (i&7);
+ if (isxdigit(i))p[cbit_xdigit + i/8] |= 1 << (i&7);
+ if (isgraph(i)) p[cbit_graph + i/8] |= 1 << (i&7);
+ if (isprint(i)) p[cbit_print + i/8] |= 1 << (i&7);
+ if (ispunct(i)) p[cbit_punct + i/8] |= 1 << (i&7);
+ if (iscntrl(i)) p[cbit_cntrl + i/8] |= 1 << (i&7);
+ }
+p += cbit_length;
+
+/* Finally, the character type table. In this, we used to exclude VT from the
+white space chars, because Perl didn't recognize it as such for \s and for
+comments within regexes. However, Perl changed at release 5.18, so PCRE changed
+at release 8.34. */
+
+for (i = 0; i < 256; i++)
+ {
+ int x = 0;
+ if (isspace(i)) x += ctype_space;
+ if (isalpha(i)) x += ctype_letter;
+ if (isdigit(i)) x += ctype_digit;
+ if (isxdigit(i)) x += ctype_xdigit;
+ if (isalnum(i) || i == '_') x += ctype_word;
+ *p++ = x;
+ }
+
+return yield;
+}
+
+/* End of pcre2_maketables.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_match.c b/test/monniaux/pcre2-10.32/pcre2_match.c
new file mode 100644
index 00000000..8741e143
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_match.c
@@ -0,0 +1,6860 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2015-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* These defines enable debugging code */
+
+/* #define DEBUG_FRAMES_DISPLAY */
+/* #define DEBUG_SHOW_OPS */
+/* #define DEBUG_SHOW_RMATCH */
+
+#ifdef DEBUG_FRAME_DISPLAY
+#include <stdarg.h>
+#endif
+
+/* These defines identify the name of the block containing "static"
+information, and fields within it. */
+
+#define NLBLOCK mb /* Block containing newline information */
+#define PSSTART start_subject /* Field containing processed string start */
+#define PSEND end_subject /* Field containing processed string end */
+
+#include "pcre2_internal.h"
+
+#define RECURSE_UNSET 0xffffffffu /* Bigger than max group number */
+
+/* Masks for identifying the public options that are permitted at match time. */
+
+#define PUBLIC_MATCH_OPTIONS \
+ (PCRE2_ANCHORED|PCRE2_ENDANCHORED|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY| \
+ PCRE2_NOTEMPTY_ATSTART|PCRE2_NO_UTF_CHECK|PCRE2_PARTIAL_HARD| \
+ PCRE2_PARTIAL_SOFT|PCRE2_NO_JIT)
+
+#define PUBLIC_JIT_MATCH_OPTIONS \
+ (PCRE2_NO_UTF_CHECK|PCRE2_NOTBOL|PCRE2_NOTEOL|PCRE2_NOTEMPTY|\
+ PCRE2_NOTEMPTY_ATSTART|PCRE2_PARTIAL_SOFT|PCRE2_PARTIAL_HARD)
+
+/* Non-error returns from and within the match() function. Error returns are
+externally defined PCRE2_ERROR_xxx codes, which are all negative. */
+
+#define MATCH_MATCH 1
+#define MATCH_NOMATCH 0
+
+/* Special internal returns used in the match() function. Make them
+sufficiently negative to avoid the external error codes. */
+
+#define MATCH_ACCEPT (-999)
+#define MATCH_KETRPOS (-998)
+/* The next 5 must be kept together and in sequence so that a test that checks
+for any one of them can use a range. */
+#define MATCH_COMMIT (-997)
+#define MATCH_PRUNE (-996)
+#define MATCH_SKIP (-995)
+#define MATCH_SKIP_ARG (-994)
+#define MATCH_THEN (-993)
+#define MATCH_BACKTRACK_MAX MATCH_THEN
+#define MATCH_BACKTRACK_MIN MATCH_COMMIT
+
+/* Group frame type values. Zero means the frame is not a group frame. The
+lower 16 bits are used for data (e.g. the capture number). Group frames are
+used for most groups so that information about the start is easily available at
+the end without having to scan back through intermediate frames (backtrack
+points). */
+
+#define GF_CAPTURE 0x00010000u
+#define GF_NOCAPTURE 0x00020000u
+#define GF_CONDASSERT 0x00030000u
+#define GF_RECURSE 0x00040000u
+
+/* Masks for the identity and data parts of the group frame type. */
+
+#define GF_IDMASK(a) ((a) & 0xffff0000u)
+#define GF_DATAMASK(a) ((a) & 0x0000ffffu)
+
+/* Repetition types */
+
+enum { REPTYPE_MIN, REPTYPE_MAX, REPTYPE_POS };
+
+/* Min and max values for the common repeats; a maximum of UINT32_MAX =>
+infinity. */
+
+static const uint32_t rep_min[] = {
+ 0, 0, /* * and *? */
+ 1, 1, /* + and +? */
+ 0, 0, /* ? and ?? */
+ 0, 0, /* dummy placefillers for OP_CR[MIN]RANGE */
+ 0, 1, 0 }; /* OP_CRPOS{STAR, PLUS, QUERY} */
+
+static const uint32_t rep_max[] = {
+ UINT32_MAX, UINT32_MAX, /* * and *? */
+ UINT32_MAX, UINT32_MAX, /* + and +? */
+ 1, 1, /* ? and ?? */
+ 0, 0, /* dummy placefillers for OP_CR[MIN]RANGE */
+ UINT32_MAX, UINT32_MAX, 1 }; /* OP_CRPOS{STAR, PLUS, QUERY} */
+
+/* Repetition types - must include OP_CRPOSRANGE (not needed above) */
+
+static const uint32_t rep_typ[] = {
+ REPTYPE_MAX, REPTYPE_MIN, /* * and *? */
+ REPTYPE_MAX, REPTYPE_MIN, /* + and +? */
+ REPTYPE_MAX, REPTYPE_MIN, /* ? and ?? */
+ REPTYPE_MAX, REPTYPE_MIN, /* OP_CRRANGE and OP_CRMINRANGE */
+ REPTYPE_POS, REPTYPE_POS, /* OP_CRPOSSTAR, OP_CRPOSPLUS */
+ REPTYPE_POS, REPTYPE_POS }; /* OP_CRPOSQUERY, OP_CRPOSRANGE */
+
+/* Numbers for RMATCH calls at backtracking points. When these lists are
+changed, the code at RETURN_SWITCH below must be updated in sync. */
+
+enum { RM1=1, RM2, RM3, RM4, RM5, RM6, RM7, RM8, RM9, RM10,
+ RM11, RM12, RM13, RM14, RM15, RM16, RM17, RM18, RM19, RM20,
+ RM21, RM22, RM23, RM24, RM25, RM26, RM27, RM28, RM29, RM30,
+ RM31, RM32, RM33, RM34, RM35, RM36 };
+
+#ifdef SUPPORT_WIDE_CHARS
+enum { RM100=100, RM101 };
+#endif
+
+#ifdef SUPPORT_UNICODE
+enum { RM200=200, RM201, RM202, RM203, RM204, RM205, RM206, RM207,
+ RM208, RM209, RM210, RM211, RM212, RM213, RM214, RM215,
+ RM216, RM217, RM218, RM219, RM220, RM221, RM222 };
+#endif
+
+/* Define short names for general fields in the current backtrack frame, which
+is always pointed to by the F variable. Occasional references to fields in
+other frames are written out explicitly. There are also some fields in the
+current frame whose names start with "temp" that are used for short-term,
+localised backtracking memory. These are #defined with Lxxx names at the point
+of use and undefined afterwards. */
+
+#define Fback_frame F->back_frame
+#define Fcapture_last F->capture_last
+#define Fcurrent_recurse F->current_recurse
+#define Fecode F->ecode
+#define Feptr F->eptr
+#define Fgroup_frame_type F->group_frame_type
+#define Flast_group_offset F->last_group_offset
+#define Flength F->length
+#define Fmark F->mark
+#define Frdepth F->rdepth
+#define Fstart_match F->start_match
+#define Foffset_top F->offset_top
+#define Foccu F->occu
+#define Fop F->op
+#define Fovector F->ovector
+#define Freturn_id F->return_id
+
+
+#ifdef DEBUG_FRAMES_DISPLAY
+/*************************************************
+* Display current frames and contents *
+*************************************************/
+
+/* This debugging function displays the current set of frames and their
+contents. It is not called automatically from anywhere, the intention being
+that calls can be inserted where necessary when debugging frame-related
+problems.
+
+Arguments:
+ f the file to write to
+ F the current top frame
+ P a previous frame of interest
+ frame_size the frame size
+ mb points to the match block
+ s identification text
+
+Returns: nothing
+*/
+
+static void
+display_frames(FILE *f, heapframe *F, heapframe *P, PCRE2_SIZE frame_size,
+ match_block *mb, const char *s, ...)
+{
+uint32_t i;
+heapframe *Q;
+va_list ap;
+va_start(ap, s);
+
+fprintf(f, "FRAMES ");
+vfprintf(f, s, ap);
+va_end(ap);
+
+if (P != NULL) fprintf(f, " P=%lu",
+ ((char *)P - (char *)(mb->match_frames))/frame_size);
+fprintf(f, "\n");
+
+for (i = 0, Q = mb->match_frames;
+ Q <= F;
+ i++, Q = (heapframe *)((char *)Q + frame_size))
+ {
+ fprintf(f, "Frame %d type=%x subj=%lu code=%d back=%lu id=%d",
+ i, Q->group_frame_type, Q->eptr - mb->start_subject, *(Q->ecode),
+ Q->back_frame, Q->return_id);
+
+ if (Q->last_group_offset == PCRE2_UNSET)
+ fprintf(f, " lgoffset=unset\n");
+ else
+ fprintf(f, " lgoffset=%lu\n", Q->last_group_offset/frame_size);
+ }
+}
+
+#endif
+
+
+
+/*************************************************
+* Process a callout *
+*************************************************/
+
+/* This function is called for all callouts, whether "standalone" or at the
+start of a conditional group. Feptr will be pointing to either OP_CALLOUT or
+OP_CALLOUT_STR. A callout block is allocated in pcre2_match() and initialized
+with fixed values.
+
+Arguments:
+ F points to the current backtracking frame
+ mb points to the match block
+ lengthptr where to return the length of the callout item
+
+Returns: the return from the callout
+ or 0 if no callout function exists
+*/
+
+static int
+do_callout(heapframe *F, match_block *mb, PCRE2_SIZE *lengthptr)
+{
+int rc;
+PCRE2_SIZE save0, save1;
+PCRE2_SIZE *callout_ovector;
+pcre2_callout_block *cb;
+
+*lengthptr = (*Fecode == OP_CALLOUT)?
+ PRIV(OP_lengths)[OP_CALLOUT] : GET(Fecode, 1 + 2*LINK_SIZE);
+
+if (mb->callout == NULL) return 0; /* No callout function provided */
+
+/* The original matching code (pre 10.30) worked directly with the ovector
+passed by the user, and this was passed to callouts. Now that the working
+ovector is in the backtracking frame, it no longer needs to reserve space for
+the overall match offsets (which would waste space in the frame). For backward
+compatibility, however, we pass capture_top and offset_vector to the callout as
+if for the extended ovector, and we ensure that the first two slots are unset
+by preserving and restoring their current contents. Picky compilers complain if
+references such as Fovector[-2] are use directly, so we set up a separate
+pointer. */
+
+callout_ovector = (PCRE2_SIZE *)(Fovector) - 2;
+
+/* The cb->version, cb->subject, cb->subject_length, and cb->start_match fields
+are set externally. The first 3 never change; the last is updated for each
+bumpalong. */
+
+cb = mb->cb;
+cb->capture_top = (uint32_t)Foffset_top/2 + 1;
+cb->capture_last = Fcapture_last;
+cb->offset_vector = callout_ovector;
+cb->mark = mb->nomatch_mark;
+cb->current_position = (PCRE2_SIZE)(Feptr - mb->start_subject);
+cb->pattern_position = GET(Fecode, 1);
+cb->next_item_length = GET(Fecode, 1 + LINK_SIZE);
+
+if (*Fecode == OP_CALLOUT) /* Numerical callout */
+ {
+ cb->callout_number = Fecode[1 + 2*LINK_SIZE];
+ cb->callout_string_offset = 0;
+ cb->callout_string = NULL;
+ cb->callout_string_length = 0;
+ }
+else /* String callout */
+ {
+ cb->callout_number = 0;
+ cb->callout_string_offset = GET(Fecode, 1 + 3*LINK_SIZE);
+ cb->callout_string = Fecode + (1 + 4*LINK_SIZE) + 1;
+ cb->callout_string_length =
+ *lengthptr - (1 + 4*LINK_SIZE) - 2;
+ }
+
+save0 = callout_ovector[0];
+save1 = callout_ovector[1];
+callout_ovector[0] = callout_ovector[1] = PCRE2_UNSET;
+rc = mb->callout(cb, mb->callout_data);
+callout_ovector[0] = save0;
+callout_ovector[1] = save1;
+cb->callout_flags = 0;
+return rc;
+}
+
+
+
+/*************************************************
+* Match a back-reference *
+*************************************************/
+
+/* This function is called only when it is known that the offset lies within
+the offsets that have so far been used in the match. Note that in caseless
+UTF-8 mode, the number of subject bytes matched may be different to the number
+of reference bytes. (In theory this could also happen in UTF-16 mode, but it
+seems unlikely.)
+
+Arguments:
+ offset index into the offset vector
+ caseless TRUE if caseless
+ F the current backtracking frame pointer
+ mb points to match block
+ lengthptr pointer for returning the length matched
+
+Returns: = 0 sucessful match; number of code units matched is set
+ < 0 no match
+ > 0 partial match
+*/
+
+static int
+match_ref(PCRE2_SIZE offset, BOOL caseless, heapframe *F, match_block *mb,
+ PCRE2_SIZE *lengthptr)
+{
+PCRE2_SPTR p;
+PCRE2_SIZE length;
+PCRE2_SPTR eptr;
+PCRE2_SPTR eptr_start;
+
+/* Deal with an unset group. The default is no match, but there is an option to
+match an empty string. */
+
+if (offset >= Foffset_top || Fovector[offset] == PCRE2_UNSET)
+ {
+ if ((mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0)
+ {
+ *lengthptr = 0;
+ return 0; /* Match */
+ }
+ else return -1; /* No match */
+ }
+
+/* Separate the caseless and UTF cases for speed. */
+
+eptr = eptr_start = Feptr;
+p = mb->start_subject + Fovector[offset];
+length = Fovector[offset+1] - Fovector[offset];
+
+if (caseless)
+ {
+#if defined SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UTF) != 0)
+ {
+ /* Match characters up to the end of the reference. NOTE: the number of
+ code units matched may differ, because in UTF-8 there are some characters
+ whose upper and lower case codes have different numbers of bytes. For
+ example, U+023A (2 bytes in UTF-8) is the upper case version of U+2C65 (3
+ bytes in UTF-8); a sequence of 3 of the former uses 6 bytes, as does a
+ sequence of two of the latter. It is important, therefore, to check the
+ length along the reference, not along the subject (earlier code did this
+ wrong). */
+
+ PCRE2_SPTR endptr = p + length;
+ while (p < endptr)
+ {
+ uint32_t c, d;
+ const ucd_record *ur;
+ if (eptr >= mb->end_subject) return 1; /* Partial match */
+ GETCHARINC(c, eptr);
+ GETCHARINC(d, p);
+ ur = GET_UCD(d);
+ if (c != d && c != (uint32_t)((int)d + ur->other_case))
+ {
+ const uint32_t *pp = PRIV(ucd_caseless_sets) + ur->caseset;
+ for (;;)
+ {
+ if (c < *pp) return -1; /* No match */
+ if (c == *pp++) break;
+ }
+ }
+ }
+ }
+ else
+#endif
+
+ /* Not in UTF mode */
+
+ {
+ for (; length > 0; length--)
+ {
+ uint32_t cc, cp;
+ if (eptr >= mb->end_subject) return 1; /* Partial match */
+ cc = UCHAR21TEST(eptr);
+ cp = UCHAR21TEST(p);
+ if (TABLE_GET(cp, mb->lcc, cp) != TABLE_GET(cc, mb->lcc, cc))
+ return -1; /* No match */
+ p++;
+ eptr++;
+ }
+ }
+ }
+
+/* In the caseful case, we can just compare the code units, whether or not we
+are in UTF mode. When partial matching, we have to do this unit-by-unit. */
+
+else
+ {
+ if (mb->partial != 0)
+ {
+ for (; length > 0; length--)
+ {
+ if (eptr >= mb->end_subject) return 1; /* Partial match */
+ if (UCHAR21INCTEST(p) != UCHAR21INCTEST(eptr)) return -1; /* No match */
+ }
+ }
+
+ /* Not partial matching */
+
+ else
+ {
+ if ((PCRE2_SIZE)(mb->end_subject - eptr) < length) return 1; /* Partial */
+ if (memcmp(p, eptr, CU2BYTES(length)) != 0) return -1; /* No match */
+ eptr += length;
+ }
+ }
+
+*lengthptr = eptr - eptr_start;
+return 0; /* Match */
+}
+
+
+
+/******************************************************************************
+*******************************************************************************
+ "Recursion" in the match() function
+
+The original match() function was highly recursive, but this proved to be the
+source of a number of problems over the years, mostly because of the relatively
+small system stacks that are commonly found. As new features were added to
+patterns, various kludges were invented to reduce the amount of stack used,
+making the code hard to understand in places.
+
+A version did exist that used individual frames on the heap instead of calling
+match() recursively, but this ran substantially slower. The current version is
+a refactoring that uses a vector of frames to remember backtracking points.
+This runs no slower, and possibly even a bit faster than the original recursive
+implementation. An initial vector of size START_FRAMES_SIZE (enough for maybe
+50 frames) is allocated on the system stack. If this is not big enough, the
+heap is used for a larger vector.
+
+*******************************************************************************
+******************************************************************************/
+
+
+
+
+/*************************************************
+* Macros for the match() function *
+*************************************************/
+
+/* These macros pack up tests that are used for partial matching several times
+in the code. We set the "hit end" flag if the pointer is at the end of the
+subject and also past the earliest inspected character (i.e. something has been
+matched, even if not part of the actual matched string). For hard partial
+matching, we then return immediately. The second one is used when we already
+know we are past the end of the subject. */
+
+#define CHECK_PARTIAL()\
+ if (mb->partial != 0 && Feptr >= mb->end_subject && \
+ Feptr > mb->start_used_ptr) \
+ { \
+ mb->hitend = TRUE; \
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; \
+ }
+
+#define SCHECK_PARTIAL()\
+ if (mb->partial != 0 && Feptr > mb->start_used_ptr) \
+ { \
+ mb->hitend = TRUE; \
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL; \
+ }
+
+/* These macros are used to implement backtracking. They simulate a recursive
+call to the match() function by means of a local vector of frames which
+remember the backtracking points. */
+
+#define RMATCH(ra,rb)\
+ {\
+ start_ecode = ra;\
+ Freturn_id = rb;\
+ goto MATCH_RECURSE;\
+ L_##rb:;\
+ }
+
+#define RRETURN(ra)\
+ {\
+ rrc = ra;\
+ goto RETURN_SWITCH;\
+ }
+
+
+
+/*************************************************
+* Match from current position *
+*************************************************/
+
+/* This function is called to run one match attempt at a single starting point
+in the subject.
+
+Performance note: It might be tempting to extract commonly used fields from the
+mb structure (e.g. end_subject) into individual variables to improve
+performance. Tests using gcc on a SPARC disproved this; in the first case, it
+made performance worse.
+
+Arguments:
+ start_eptr starting character in subject
+ start_ecode starting position in compiled code
+ ovector pointer to the final output vector
+ oveccount number of pairs in ovector
+ top_bracket number of capturing parentheses in the pattern
+ frame_size size of each backtracking frame
+ mb pointer to "static" variables block
+
+Returns: MATCH_MATCH if matched ) these values are >= 0
+ MATCH_NOMATCH if failed to match )
+ negative MATCH_xxx value for PRUNE, SKIP, etc
+ negative PCRE2_ERROR_xxx value if aborted by an error condition
+ (e.g. stopped by repeated call or depth limit)
+*/
+
+static int
+match(PCRE2_SPTR start_eptr, PCRE2_SPTR start_ecode, PCRE2_SIZE *ovector,
+ uint16_t oveccount, uint16_t top_bracket, PCRE2_SIZE frame_size,
+ match_block *mb)
+{
+/* Frame-handling variables */
+
+heapframe *F; /* Current frame pointer */
+heapframe *N = NULL; /* Temporary frame pointers */
+heapframe *P = NULL;
+heapframe *assert_accept_frame; /* For passing back the frame with captures */
+PCRE2_SIZE frame_copy_size; /* Amount to copy when creating a new frame */
+
+/* Local variables that do not need to be preserved over calls to RRMATCH(). */
+
+PCRE2_SPTR bracode; /* Temp pointer to start of group */
+PCRE2_SIZE offset; /* Used for group offsets */
+PCRE2_SIZE length; /* Used for various length calculations */
+
+int rrc; /* Return from functions & backtracking "recursions" */
+#ifdef SUPPORT_UNICODE
+int proptype; /* Type of character property */
+#endif
+
+uint32_t i; /* Used for local loops */
+uint32_t fc; /* Character values */
+uint32_t number; /* Used for group and other numbers */
+uint32_t reptype = 0; /* Type of repetition (0 to avoid compiler warning) */
+uint32_t group_frame_type; /* Specifies type for new group frames */
+
+BOOL condition; /* Used in conditional groups */
+BOOL cur_is_word; /* Used in "word" tests */
+BOOL prev_is_word; /* Used in "word" tests */
+
+/* UTF flag */
+
+#ifdef SUPPORT_UNICODE
+BOOL utf = (mb->poptions & PCRE2_UTF) != 0;
+#else
+BOOL utf = FALSE;
+#endif
+
+/* This is the length of the last part of a backtracking frame that must be
+copied when a new frame is created. */
+
+frame_copy_size = frame_size - offsetof(heapframe, eptr);
+
+/* Set up the first current frame at the start of the vector, and initialize
+fields that are not reset for new frames. */
+
+F = mb->match_frames;
+Frdepth = 0; /* "Recursion" depth */
+Fcapture_last = 0; /* Number of most recent capture */
+Fcurrent_recurse = RECURSE_UNSET; /* Not pattern recursing. */
+Fstart_match = Feptr = start_eptr; /* Current data pointer and start match */
+Fmark = NULL; /* Most recent mark */
+Foffset_top = 0; /* End of captures within the frame */
+Flast_group_offset = PCRE2_UNSET; /* Saved frame of most recent group */
+group_frame_type = 0; /* Not a start of group frame */
+goto NEW_FRAME; /* Start processing with this frame */
+
+/* Come back here when we want to create a new frame for remembering a
+backtracking point. */
+
+MATCH_RECURSE:
+
+/* Set up a new backtracking frame. If the vector is full, get a new one
+on the heap, doubling the size, but constrained by the heap limit. */
+
+N = (heapframe *)((char *)F + frame_size);
+if (N >= mb->match_frames_top)
+ {
+ PCRE2_SIZE newsize = mb->frame_vector_size * 2;
+ heapframe *new;
+
+ if ((newsize / 1024) > mb->heap_limit)
+ {
+ PCRE2_SIZE maxsize = ((mb->heap_limit * 1024)/frame_size) * frame_size;
+ if (mb->frame_vector_size >= maxsize) return PCRE2_ERROR_HEAPLIMIT;
+ newsize = maxsize;
+ }
+
+ new = mb->memctl.malloc(newsize, mb->memctl.memory_data);
+ if (new == NULL) return PCRE2_ERROR_NOMEMORY;
+ memcpy(new, mb->match_frames, mb->frame_vector_size);
+
+ F = (heapframe *)((char *)new + ((char *)F - (char *)mb->match_frames));
+ N = (heapframe *)((char *)F + frame_size);
+
+ if (mb->match_frames != mb->stack_frames)
+ mb->memctl.free(mb->match_frames, mb->memctl.memory_data);
+ mb->match_frames = new;
+ mb->match_frames_top = (heapframe *)((char *)mb->match_frames + newsize);
+ mb->frame_vector_size = newsize;
+ }
+
+#ifdef DEBUG_SHOW_RMATCH
+fprintf(stderr, "++ RMATCH %2d frame=%d", Freturn_id, Frdepth + 1);
+if (group_frame_type != 0)
+ {
+ fprintf(stderr, " type=%x ", group_frame_type);
+ switch (GF_IDMASK(group_frame_type))
+ {
+ case GF_CAPTURE:
+ fprintf(stderr, "capture=%d", GF_DATAMASK(group_frame_type));
+ break;
+
+ case GF_NOCAPTURE:
+ fprintf(stderr, "nocapture op=%d", GF_DATAMASK(group_frame_type));
+ break;
+
+ case GF_CONDASSERT:
+ fprintf(stderr, "condassert op=%d", GF_DATAMASK(group_frame_type));
+ break;
+
+ case GF_RECURSE:
+ fprintf(stderr, "recurse=%d", GF_DATAMASK(group_frame_type));
+ break;
+
+ default:
+ fprintf(stderr, "*** unknown ***");
+ break;
+ }
+ }
+fprintf(stderr, "\n");
+#endif
+
+/* Copy those fields that must be copied into the new frame, increase the
+"recursion" depth (i.e. the new frame's index) and then make the new frame
+current. */
+
+memcpy((char *)N + offsetof(heapframe, eptr),
+ (char *)F + offsetof(heapframe, eptr),
+ frame_copy_size);
+
+N->rdepth = Frdepth + 1;
+F = N;
+
+/* Carry on processing with a new frame. */
+
+NEW_FRAME:
+Fgroup_frame_type = group_frame_type;
+Fecode = start_ecode; /* Starting code pointer */
+Fback_frame = frame_size; /* Default is go back one frame */
+
+/* If this is a special type of group frame, remember its offset for quick
+access at the end of the group. If this is a recursion, set a new current
+recursion value. */
+
+if (group_frame_type != 0)
+ {
+ Flast_group_offset = (char *)F - (char *)mb->match_frames;
+ if (GF_IDMASK(group_frame_type) == GF_RECURSE)
+ Fcurrent_recurse = GF_DATAMASK(group_frame_type);
+ group_frame_type = 0;
+ }
+
+
+/* ========================================================================= */
+/* This is the main processing loop. First check that we haven't recorded too
+many backtracks (search tree is too large), or that we haven't exceeded the
+recursive depth limit (used too many backtracking frames). If not, process the
+opcodes. */
+
+if (mb->match_call_count++ >= mb->match_limit) return PCRE2_ERROR_MATCHLIMIT;
+if (Frdepth >= mb->match_limit_depth) return PCRE2_ERROR_DEPTHLIMIT;
+
+for (;;)
+ {
+#ifdef DEBUG_SHOW_OPS
+fprintf(stderr, "++ op=%d\n", *Fecode);
+#endif
+
+ Fop = (uint8_t)(*Fecode); /* Cast needed for 16-bit and 32-bit modes */
+ switch(Fop)
+ {
+ /* ===================================================================== */
+ /* Before OP_ACCEPT there may be any number of OP_CLOSE opcodes, to close
+ any currently open capturing brackets. Unlike reaching the end of a group,
+ where we know the starting frame is at the top of the chained frames, in
+ this case we have to search back for the relevant frame in case other types
+ of group that use chained frames have intervened. Multiple OP_CLOSEs always
+ come innermost first, which matches the chain order. We can ignore this in
+ a recursion, because captures are not passed out of recursions. */
+
+ case OP_CLOSE:
+ if (Fcurrent_recurse == RECURSE_UNSET)
+ {
+ number = GET2(Fecode, 1);
+ offset = Flast_group_offset;
+ for(;;)
+ {
+ if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL;
+ N = (heapframe *)((char *)mb->match_frames + offset);
+ P = (heapframe *)((char *)N - frame_size);
+ if (N->group_frame_type == (GF_CAPTURE | number)) break;
+ offset = P->last_group_offset;
+ }
+ offset = (number << 1) - 2;
+ Fcapture_last = number;
+ Fovector[offset] = P->eptr - mb->start_subject;
+ Fovector[offset+1] = Feptr - mb->start_subject;
+ if (offset >= Foffset_top) Foffset_top = offset + 2;
+ }
+ Fecode += PRIV(OP_lengths)[*Fecode];
+ break;
+
+
+ /* ===================================================================== */
+ /* Real or forced end of the pattern, assertion, or recursion. In an
+ assertion ACCEPT, update the last used pointer and remember the current
+ frame so that the captures and mark can be fished out of it. */
+
+ case OP_ASSERT_ACCEPT:
+ if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+ assert_accept_frame = F;
+ RRETURN(MATCH_ACCEPT);
+
+ /* If recursing, we have to find the most recent recursion. */
+
+ case OP_ACCEPT:
+ case OP_END:
+
+ /* Handle end of a recursion. */
+
+ if (Fcurrent_recurse != RECURSE_UNSET)
+ {
+ offset = Flast_group_offset;
+ for(;;)
+ {
+ if (offset == PCRE2_UNSET) return PCRE2_ERROR_INTERNAL;
+ N = (heapframe *)((char *)mb->match_frames + offset);
+ P = (heapframe *)((char *)N - frame_size);
+ if (GF_IDMASK(N->group_frame_type) == GF_RECURSE) break;
+ offset = P->last_group_offset;
+ }
+
+ /* N is now the frame of the recursion; the previous frame is at the
+ OP_RECURSE position. Go back there, copying the current subject position
+ and mark, and move on past the OP_RECURSE. */
+
+ P->eptr = Feptr;
+ P->mark = Fmark;
+ F = P;
+ Fecode += 1 + LINK_SIZE;
+ continue;
+ }
+
+ /* Not a recursion. Fail for an empty string match if either PCRE2_NOTEMPTY
+ is set, or if PCRE2_NOTEMPTY_ATSTART is set and we have matched at the
+ start of the subject. In both cases, backtracking will then try other
+ alternatives, if any. */
+
+ if (Feptr == Fstart_match &&
+ ((mb->moptions & PCRE2_NOTEMPTY) != 0 ||
+ ((mb->moptions & PCRE2_NOTEMPTY_ATSTART) != 0 &&
+ Fstart_match == mb->start_subject + mb->start_offset)))
+ RRETURN(MATCH_NOMATCH);
+
+ /* Also fail if PCRE2_ENDANCHORED is set and the end of the match is not
+ the end of the subject. After (*ACCEPT) we fail the entire match (at this
+ position) but backtrack on reaching the end of the pattern. */
+
+ if (Feptr < mb->end_subject &&
+ ((mb->moptions | mb->poptions) & PCRE2_ENDANCHORED) != 0)
+ {
+ if (Fop == OP_END) RRETURN(MATCH_NOMATCH);
+ return MATCH_NOMATCH;
+ }
+
+ /* We have a successful match of the whole pattern. Record the result and
+ then do a direct return from the function. If there is space in the offset
+ vector, set any pairs that follow the highest-numbered captured string but
+ are less than the number of capturing groups in the pattern to PCRE2_UNSET.
+ It is documented that this happens. "Gaps" are set to PCRE2_UNSET
+ dynamically. It is only those at the end that need setting here. */
+
+ mb->end_match_ptr = Feptr; /* Record where we ended */
+ mb->end_offset_top = Foffset_top; /* and how many extracts were taken */
+ mb->mark = Fmark; /* and the last success mark */
+ if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+
+ ovector[0] = Fstart_match - mb->start_subject;
+ ovector[1] = Feptr - mb->start_subject;
+
+ /* Set i to the smaller of the sizes of the external and frame ovectors. */
+
+ i = 2 * ((top_bracket + 1 > oveccount)? oveccount : top_bracket + 1);
+ memcpy(ovector + 2, Fovector, (i - 2) * sizeof(PCRE2_SIZE));
+ while (--i >= Foffset_top + 2) ovector[i] = PCRE2_UNSET;
+ return MATCH_MATCH; /* Note: NOT RRETURN */
+
+
+ /*===================================================================== */
+ /* Match any single character type except newline; have to take care with
+ CRLF newlines and partial matching. */
+
+ case OP_ANY:
+ if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+ if (mb->partial != 0 &&
+ Feptr == mb->end_subject - 1 &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ UCHAR21TEST(Feptr) == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ /* Fall through */
+
+ /* Match any single character whatsoever. */
+
+ case OP_ALLANY:
+ if (Feptr >= mb->end_subject) /* DO NOT merge the Feptr++ here; it must */
+ { /* not be updated before SCHECK_PARTIAL. */
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ Feptr++;
+#ifdef SUPPORT_UNICODE
+ if (utf) ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+#endif
+ Fecode++;
+ break;
+
+
+ /* ===================================================================== */
+ /* Match a single code unit, even in UTF mode. This opcode really does
+ match any code unit, even newline. (It really should be called ANYCODEUNIT,
+ of course - the byte name is from pre-16 bit days.) */
+
+ case OP_ANYBYTE:
+ if (Feptr >= mb->end_subject) /* DO NOT merge the Feptr++ here; it must */
+ { /* not be updated before SCHECK_PARTIAL. */
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ Feptr++;
+ Fecode++;
+ break;
+
+
+ /* ===================================================================== */
+ /* Match a single character, casefully */
+
+ case OP_CHAR:
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ Flength = 1;
+ Fecode++;
+ GETCHARLEN(fc, Fecode, Flength);
+ if (Flength > (PCRE2_SIZE)(mb->end_subject - Feptr))
+ {
+ CHECK_PARTIAL(); /* Not SCHECK_PARTIAL() */
+ RRETURN(MATCH_NOMATCH);
+ }
+ for (; Flength > 0; Flength--)
+ {
+ if (*Fecode++ != UCHAR21INC(Feptr)) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ if (mb->end_subject - Feptr < 1)
+ {
+ SCHECK_PARTIAL(); /* This one can use SCHECK_PARTIAL() */
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Fecode[1] != *Feptr++) RRETURN(MATCH_NOMATCH);
+ Fecode += 2;
+ }
+ break;
+
+
+ /* ===================================================================== */
+ /* Match a single character, caselessly. If we are at the end of the
+ subject, give up immediately. We get here only when the pattern character
+ has at most one other case. Characters with more than two cases are coded
+ as OP_PROP with the pseudo-property PT_CLIST. */
+
+ case OP_CHARI:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ Flength = 1;
+ Fecode++;
+ GETCHARLEN(fc, Fecode, Flength);
+
+ /* If the pattern character's value is < 128, we know that its other case
+ (if any) is also < 128 (and therefore only one code unit long in all
+ code-unit widths), so we can use the fast lookup table. We checked above
+ that there is at least one character left in the subject. */
+
+ if (fc < 128)
+ {
+ uint32_t cc = UCHAR21(Feptr);
+ if (mb->lcc[fc] != TABLE_GET(cc, mb->lcc, cc)) RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ Feptr++;
+ }
+
+ /* Otherwise we must pick up the subject character and use Unicode
+ property support to test its other case. Note that we cannot use the
+ value of "Flength" to check for sufficient bytes left, because the other
+ case of the character may have more or fewer code units. */
+
+ else
+ {
+ uint32_t dc;
+ GETCHARINC(dc, Feptr);
+ Fecode += Flength;
+ if (dc != fc && dc != UCD_OTHERCASE(fc)) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF mode; use the table for characters < 256. */
+ {
+ if (TABLE_GET(Fecode[1], mb->lcc, Fecode[1])
+ != TABLE_GET(*Feptr, mb->lcc, *Feptr)) RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ Fecode += 2;
+ }
+ break;
+
+
+ /* ===================================================================== */
+ /* Match not a single character. */
+
+ case OP_NOT:
+ case OP_NOTI:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t ch;
+ Fecode++;
+ GETCHARINC(ch, Fecode);
+ GETCHARINC(fc, Feptr);
+ if (ch == fc)
+ {
+ RRETURN(MATCH_NOMATCH); /* Caseful match */
+ }
+ else if (Fop == OP_NOTI) /* If caseless */
+ {
+ if (ch > 127)
+ ch = UCD_OTHERCASE(ch);
+ else
+ ch = TABLE_GET(ch, mb->fcc, ch);
+ if (ch == fc) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ {
+ uint32_t ch = Fecode[1];
+ fc = *Feptr++;
+ if (ch == fc || (Fop == OP_NOTI && TABLE_GET(ch, mb->fcc, ch) == fc))
+ RRETURN(MATCH_NOMATCH);
+ Fecode += 2;
+ }
+ break;
+
+
+ /* ===================================================================== */
+ /* Match a single character repeatedly. */
+
+#define Loclength F->temp_size
+#define Lstart_eptr F->temp_sptr[0]
+#define Lcharptr F->temp_sptr[1]
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Lc F->temp_32[2]
+#define Loc F->temp_32[3]
+
+ case OP_EXACT:
+ case OP_EXACTI:
+ Lmin = Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATCHAR;
+
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATCHAR;
+
+ case OP_UPTO:
+ case OP_UPTOI:
+ reptype = REPTYPE_MAX;
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATCHAR;
+
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ reptype = REPTYPE_MIN;
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATCHAR;
+
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = UINT32_MAX;
+ Fecode++;
+ goto REPEATCHAR;
+
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ reptype = REPTYPE_POS;
+ Lmin = 1;
+ Lmax = UINT32_MAX;
+ Fecode++;
+ goto REPEATCHAR;
+
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = 1;
+ Fecode++;
+ goto REPEATCHAR;
+
+ case OP_STAR:
+ case OP_STARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ fc = *Fecode++ - ((Fop < OP_STARI)? OP_STAR : OP_STARI);
+ Lmin = rep_min[fc];
+ Lmax = rep_max[fc];
+ reptype = rep_typ[fc];
+
+ /* Common code for all repeated single-character matches. We first check
+ for the minimum number of characters. If the minimum equals the maximum, we
+ are done. Otherwise, if minimizing, check the rest of the pattern for a
+ match; if there isn't one, advance up to the maximum, one character at a
+ time.
+
+ If maximizing, advance up to the maximum number of matching characters,
+ until Feptr is past the end of the maximum run. If possessive, we are
+ then done (no backing up). Otherwise, match at this position; anything
+ other than no match is immediately returned. For nomatch, back up one
+ character, unless we are matching \R and the last thing matched was
+ \r\n, in which case, back up two code units until we reach the first
+ optional character position.
+
+ The various UTF/non-UTF and caseful/caseless cases are handled separately,
+ for speed. */
+
+ REPEATCHAR:
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ Flength = 1;
+ Lcharptr = Fecode;
+ GETCHARLEN(fc, Fecode, Flength);
+ Fecode += Flength;
+
+ /* Handle multi-code-unit character matching, caseful and caseless. */
+
+ if (Flength > 1)
+ {
+ uint32_t othercase;
+
+ if (Fop >= OP_STARI && /* Caseless */
+ (othercase = UCD_OTHERCASE(fc)) != fc)
+ Loclength = PRIV(ord2utf)(othercase, Foccu);
+ else Loclength = 0;
+
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr <= mb->end_subject - Flength &&
+ memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength;
+ else if (Loclength > 0 &&
+ Feptr <= mb->end_subject - Loclength &&
+ memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0)
+ Feptr += Loclength;
+ else
+ {
+ CHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+
+ if (Lmin == Lmax) continue;
+
+ if (reptype == REPTYPE_MIN)
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM202);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr <= mb->end_subject - Flength &&
+ memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0) Feptr += Flength;
+ else if (Loclength > 0 &&
+ Feptr <= mb->end_subject - Loclength &&
+ memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0)
+ Feptr += Loclength;
+ else
+ {
+ CHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+ }
+
+ else /* Maximize */
+ {
+ Lstart_eptr = Feptr;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr <= mb->end_subject - Flength &&
+ memcmp(Feptr, Lcharptr, CU2BYTES(Flength)) == 0)
+ Feptr += Flength;
+ else if (Loclength > 0 &&
+ Feptr <= mb->end_subject - Loclength &&
+ memcmp(Feptr, Foccu, CU2BYTES(Loclength)) == 0)
+ Feptr += Loclength;
+ else
+ {
+ CHECK_PARTIAL();
+ break;
+ }
+ }
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+ go too far. */
+
+ if (reptype != REPTYPE_POS) for(;;)
+ {
+ if (Feptr <= Lstart_eptr) break;
+ RMATCH(Fecode, RM203);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ BACKCHAR(Feptr);
+ }
+ }
+ break; /* End of repeated wide character handling */
+ }
+
+ /* Length of UTF character is 1. Put it into the preserved variable and
+ fall through to the non-UTF code. */
+
+ Lc = fc;
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* When not in UTF mode, load a single-code-unit character. Then proceed as
+ above. */
+
+ Lc = *Fecode++;
+
+ /* Caseless comparison */
+
+ if (Fop >= OP_STARI)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ /* Lc must be < 128 in UTF-8 mode. */
+ Loc = mb->fcc[Lc];
+#else /* 16-bit & 32-bit */
+#ifdef SUPPORT_UNICODE
+ if (utf && Lc > 127) Loc = UCD_OTHERCASE(Lc);
+ else
+#endif /* SUPPORT_UNICODE */
+ Loc = TABLE_GET(Lc, mb->fcc, Lc);
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+ for (i = 1; i <= Lmin; i++)
+ {
+ uint32_t cc; /* Faster than PCRE2_UCHAR */
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21TEST(Feptr);
+ if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ if (Lmin == Lmax) continue;
+
+ if (reptype == REPTYPE_MIN)
+ {
+ for (;;)
+ {
+ uint32_t cc; /* Faster than PCRE2_UCHAR */
+ RMATCH(Fecode, RM25);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21TEST(Feptr);
+ if (Lc != cc && Loc != cc) RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ /* Control never gets here */
+ }
+
+ else /* Maximize */
+ {
+ Lstart_eptr = Feptr;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ uint32_t cc; /* Faster than PCRE2_UCHAR */
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ cc = UCHAR21TEST(Feptr);
+ if (Lc != cc && Loc != cc) break;
+ Feptr++;
+ }
+ if (reptype != REPTYPE_POS) for (;;)
+ {
+ if (Feptr == Lstart_eptr) break;
+ RMATCH(Fecode, RM26);
+ Feptr--;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ }
+ }
+
+ /* Caseful comparisons (includes all multi-byte characters) */
+
+ else
+ {
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH);
+ }
+
+ if (Lmin == Lmax) continue;
+
+ if (reptype == REPTYPE_MIN)
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM27);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lc != UCHAR21INCTEST(Feptr)) RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+ else /* Maximize */
+ {
+ Lstart_eptr = Feptr;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+
+ if (Lc != UCHAR21TEST(Feptr)) break;
+ Feptr++;
+ }
+
+ if (reptype != REPTYPE_POS) for (;;)
+ {
+ if (Feptr <= Lstart_eptr) break;
+ RMATCH(Fecode, RM28);
+ Feptr--;
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+ }
+ }
+ break;
+
+#undef Loclength
+#undef Lstart_eptr
+#undef Lcharptr
+#undef Lmin
+#undef Lmax
+#undef Lc
+#undef Loc
+
+
+ /* ===================================================================== */
+ /* Match a negated single one-byte character repeatedly. This is almost a
+ repeat of the code for a repeated single character, but I haven't found a
+ nice way of commoning these up that doesn't require a test of the
+ positive/negative option for each character match. Maybe that wouldn't add
+ very much to the time taken, but character matching *is* what this is all
+ about... */
+
+#define Lstart_eptr F->temp_sptr[0]
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Lc F->temp_32[2]
+#define Loc F->temp_32[3]
+
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ Lmin = Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ reptype = REPTYPE_MAX;
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ reptype = REPTYPE_MIN;
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = UINT32_MAX;
+ Fecode++;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ reptype = REPTYPE_POS;
+ Lmin = 1;
+ Lmax = UINT32_MAX;
+ Fecode++;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = 1;
+ Fecode++;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATNOTCHAR;
+
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ fc = *Fecode++ - ((Fop >= OP_NOTSTARI)? OP_NOTSTARI: OP_NOTSTAR);
+ Lmin = rep_min[fc];
+ Lmax = rep_max[fc];
+ reptype = rep_typ[fc];
+
+ /* Common code for all repeated single-character non-matches. */
+
+ REPEATNOTCHAR:
+ GETCHARINCTEST(Lc, Fecode);
+
+ /* The code is duplicated for the caseless and caseful cases, for speed,
+ since matching characters is likely to be quite common. First, ensure the
+ minimum number of matches are present. If Lmin = Lmax, we are done.
+ Otherwise, if minimizing, keep trying the rest of the expression and
+ advancing one matching character if failing, up to the maximum.
+ Alternatively, if maximizing, find the maximum number of characters and
+ work backwards. */
+
+ if (Fop >= OP_NOTSTARI) /* Caseless */
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf && Lc > 127)
+ Loc = UCD_OTHERCASE(Lc);
+ else
+#endif /* SUPPORT_UNICODE */
+
+ Loc = TABLE_GET(Lc, mb->fcc, Lc); /* Other case from table */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t d;
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(d, Feptr);
+ if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF mode */
+ {
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ }
+
+ if (Lmin == Lmax) continue; /* Finished for exact count */
+
+ if (reptype == REPTYPE_MIN)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t d;
+ for (;;)
+ {
+ RMATCH(Fecode, RM204);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(d, Feptr);
+ if (Lc == d || Loc == d) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif /*SUPPORT_UNICODE */
+
+ /* Not UTF mode */
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM29);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lc == *Feptr || Loc == *Feptr) RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* Maximize case */
+
+ else
+ {
+ Lstart_eptr = Feptr;
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t d;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(d, Feptr, len);
+ if (Lc == d || Loc == d) break;
+ Feptr += len;
+ }
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+ go too far. */
+
+ if (reptype != REPTYPE_POS) for(;;)
+ {
+ if (Feptr <= Lstart_eptr) break;
+ RMATCH(Fecode, RM205);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ BACKCHAR(Feptr);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF mode */
+ {
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (Lc == *Feptr || Loc == *Feptr) break;
+ Feptr++;
+ }
+ if (reptype != REPTYPE_POS) for (;;)
+ {
+ if (Feptr == Lstart_eptr) break;
+ RMATCH(Fecode, RM30);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ }
+ }
+ }
+ }
+
+ /* Caseful comparisons */
+
+ else
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t d;
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(d, Feptr);
+ if (Lc == d) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH);
+ }
+ }
+
+ if (Lmin == Lmax) continue;
+
+ if (reptype == REPTYPE_MIN)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t d;
+ for (;;)
+ {
+ RMATCH(Fecode, RM206);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(d, Feptr);
+ if (Lc == d) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM31);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lc == *Feptr++) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* Maximize case */
+
+ else
+ {
+ Lstart_eptr = Feptr;
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t d;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(d, Feptr, len);
+ if (Lc == d) break;
+ Feptr += len;
+ }
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+ go too far. */
+
+ if (reptype != REPTYPE_POS) for(;;)
+ {
+ if (Feptr <= Lstart_eptr) break;
+ RMATCH(Fecode, RM207);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ BACKCHAR(Feptr);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (Lc == *Feptr) break;
+ Feptr++;
+ }
+ if (reptype != REPTYPE_POS) for (;;)
+ {
+ if (Feptr == Lstart_eptr) break;
+ RMATCH(Fecode, RM32);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ }
+ }
+ }
+ }
+ break;
+
+#undef Lstart_eptr
+#undef Lmin
+#undef Lmax
+#undef Lc
+#undef Loc
+
+
+ /* ===================================================================== */
+ /* Match a bit-mapped character class, possibly repeatedly. These opcodes
+ are used when all the characters in the class have values in the range
+ 0-255, and either the matching is caseful, or the characters are in the
+ range 0-127 when UTF processing is enabled. The only difference between
+ OP_CLASS and OP_NCLASS occurs when a data character outside the range is
+ encountered. */
+
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Lstart_eptr F->temp_sptr[0]
+#define Lbyte_map_address F->temp_sptr[1]
+#define Lbyte_map ((unsigned char *)Lbyte_map_address)
+
+ case OP_NCLASS:
+ case OP_CLASS:
+ {
+ Lbyte_map_address = Fecode + 1; /* Save for matching */
+ Fecode += 1 + (32 / sizeof(PCRE2_UCHAR)); /* Advance past the item */
+
+ /* Look past the end of the item to see if there is repeat information
+ following. Then obey similar code to character type repeats. */
+
+ switch (*Fecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ case OP_CRPOSQUERY:
+ fc = *Fecode++ - OP_CRSTAR;
+ Lmin = rep_min[fc];
+ Lmax = rep_max[fc];
+ reptype = rep_typ[fc];
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ Lmin = GET2(Fecode, 1);
+ Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+ if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */
+ reptype = rep_typ[*Fecode - OP_CRSTAR];
+ Fecode += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default: /* No repeat follows */
+ Lmin = Lmax = 1;
+ break;
+ }
+
+ /* First, ensure the minimum number of matches are present. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ if (fc > 255)
+ {
+ if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+ }
+ else
+ if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ fc = *Feptr++;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (fc > 255)
+ {
+ if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+ }
+ else
+#endif
+ if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+
+ /* If Lmax == Lmin we are done. Continue with main loop. */
+
+ if (Lmin == Lmax) continue;
+
+ /* If minimizing, keep testing the rest of the expression and advancing
+ the pointer while it matches the class. */
+
+ if (reptype == REPTYPE_MIN)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM200);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ if (fc > 255)
+ {
+ if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+ }
+ else
+ if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM23);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ fc = *Feptr++;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (fc > 255)
+ {
+ if (Fop == OP_CLASS) RRETURN(MATCH_NOMATCH);
+ }
+ else
+#endif
+ if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, find the longest possible run, then work backwards. */
+
+ else
+ {
+ Lstart_eptr = Feptr;
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc > 255)
+ {
+ if (Fop == OP_CLASS) break;
+ }
+ else
+ if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) break;
+ Feptr += len;
+ }
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+ go too far. */
+
+ for (;;)
+ {
+ RMATCH(Fecode, RM201);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Feptr-- <= Lstart_eptr) break; /* Tried at original position */
+ BACKCHAR(Feptr);
+ }
+ }
+ else
+#endif
+ /* Not UTF mode */
+ {
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ fc = *Feptr;
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (fc > 255)
+ {
+ if (Fop == OP_CLASS) break;
+ }
+ else
+#endif
+ if ((Lbyte_map[fc/8] & (1 << (fc&7))) == 0) break;
+ Feptr++;
+ }
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ while (Feptr >= Lstart_eptr)
+ {
+ RMATCH(Fecode, RM24);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ }
+ }
+
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ /* Control never gets here */
+
+#undef Lbyte_map_address
+#undef Lbyte_map
+#undef Lstart_eptr
+#undef Lmin
+#undef Lmax
+
+
+ /* ===================================================================== */
+ /* Match an extended character class. In the 8-bit library, this opcode is
+ encountered only when UTF-8 mode mode is supported. In the 16-bit and
+ 32-bit libraries, codepoints greater than 255 may be encountered even when
+ UTF is not supported. */
+
+#define Lstart_eptr F->temp_sptr[0]
+#define Lxclass_data F->temp_sptr[1]
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ {
+ Lxclass_data = Fecode + 1 + LINK_SIZE; /* Save for matching */
+ Fecode += GET(Fecode, 1); /* Advance past the item */
+
+ switch (*Fecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ case OP_CRPOSQUERY:
+ fc = *Fecode++ - OP_CRSTAR;
+ Lmin = rep_min[fc];
+ Lmax = rep_max[fc];
+ reptype = rep_typ[fc];
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ Lmin = GET2(Fecode, 1);
+ Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+ if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */
+ reptype = rep_typ[*Fecode - OP_CRSTAR];
+ Fecode += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default: /* No repeat follows */
+ Lmin = Lmax = 1;
+ break;
+ }
+
+ /* First, ensure the minimum number of matches are present. */
+
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH);
+ }
+
+ /* If Lmax == Lmin we can just continue with the main loop. */
+
+ if (Lmin == Lmax) continue;
+
+ /* If minimizing, keep testing the rest of the expression and advancing
+ the pointer while it matches the class. */
+
+ if (reptype == REPTYPE_MIN)
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM100);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (!PRIV(xclass)(fc, Lxclass_data, utf)) RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, find the longest possible run, then work backwards. */
+
+ else
+ {
+ Lstart_eptr = Feptr;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+#ifdef SUPPORT_UNICODE
+ GETCHARLENTEST(fc, Feptr, len);
+#else
+ fc = *Feptr;
+#endif
+ if (!PRIV(xclass)(fc, Lxclass_data, utf)) break;
+ Feptr += len;
+ }
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+ go too far. */
+
+ for(;;)
+ {
+ RMATCH(Fecode, RM101);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Feptr-- <= Lstart_eptr) break; /* Tried at original position */
+#ifdef SUPPORT_UNICODE
+ if (utf) BACKCHAR(Feptr);
+#endif
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+
+ /* Control never gets here */
+ }
+#endif /* SUPPORT_WIDE_CHARS: end of XCLASS */
+
+#undef Lstart_eptr
+#undef Lxclass_data
+#undef Lmin
+#undef Lmax
+
+
+ /* ===================================================================== */
+ /* Match various character types when PCRE2_UCP is not set. These opcodes
+ are not generated when PCRE2_UCP is set - instead appropriate property
+ tests are compiled. */
+
+ case OP_NOT_DIGIT:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_DIGIT:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_WHITESPACE:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_WORDCHAR:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (!CHMAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_ANYNL:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+
+ case CHAR_CR:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ }
+ else if (UCHAR21TEST(Feptr) == CHAR_LF) Feptr++;
+ break;
+
+ case CHAR_LF:
+ break;
+
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ Fecode++;
+ break;
+
+ case OP_NOT_HSPACE:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ HSPACE_CASES: RRETURN(MATCH_NOMATCH); /* Byte and multibyte cases */
+ default: break;
+ }
+ Fecode++;
+ break;
+
+ case OP_HSPACE:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ HSPACE_CASES: break; /* Byte and multibyte cases */
+ default: RRETURN(MATCH_NOMATCH);
+ }
+ Fecode++;
+ break;
+
+ case OP_NOT_VSPACE:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ VSPACE_CASES: RRETURN(MATCH_NOMATCH);
+ default: break;
+ }
+ Fecode++;
+ break;
+
+ case OP_VSPACE:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ VSPACE_CASES: break;
+ default: RRETURN(MATCH_NOMATCH);
+ }
+ Fecode++;
+ break;
+
+
+#ifdef SUPPORT_UNICODE
+
+ /* ===================================================================== */
+ /* Check the next character by Unicode property. We will get here only
+ if the support is in the binary; otherwise a compile-time error occurs. */
+
+ case OP_PROP:
+ case OP_NOTPROP:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ {
+ const uint32_t *cp;
+ const ucd_record *prop = GET_UCD(fc);
+
+ switch(Fecode[1])
+ {
+ case PT_ANY:
+ if (Fop == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ break;
+
+ case PT_LAMP:
+ if ((prop->chartype == ucp_Lu ||
+ prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt) == (Fop == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case PT_GC:
+ if ((Fecode[2] != PRIV(ucp_gentype)[prop->chartype]) == (Fop == OP_PROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case PT_PC:
+ if ((Fecode[2] != prop->chartype) == (Fop == OP_PROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case PT_SC:
+ if ((Fecode[2] != prop->script) == (Fop == OP_PROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ /* These are specials */
+
+ case PT_ALNUM:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N) == (Fop == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(fc)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ if (Fop == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ break;
+
+ default:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) ==
+ (Fop == OP_NOTPROP)) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ break;
+
+ case PT_WORD:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N ||
+ fc == CHAR_UNDERSCORE) == (Fop == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case PT_CLIST:
+ cp = PRIV(ucd_caseless_sets) + Fecode[2];
+ for (;;)
+ {
+ if (fc < *cp)
+ { if (Fop == OP_PROP) { RRETURN(MATCH_NOMATCH); } else break; }
+ if (fc == *cp++)
+ { if (Fop == OP_PROP) break; else { RRETURN(MATCH_NOMATCH); } }
+ }
+ break;
+
+ case PT_UCNC:
+ if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+ fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+ fc >= 0xe000) == (Fop == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ /* This should never occur */
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+
+ Fecode += 3;
+ }
+ break;
+
+
+ /* ===================================================================== */
+ /* Match an extended Unicode sequence. We will get here only if the support
+ is in the binary; otherwise a compile-time error occurs. */
+
+ case OP_EXTUNI:
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+ Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject, utf,
+ NULL);
+ }
+ CHECK_PARTIAL();
+ Fecode++;
+ break;
+
+#endif /* SUPPORT_UNICODE */
+
+
+ /* ===================================================================== */
+ /* Match a single character type repeatedly. Note that the property type
+ does not need to be in a stack frame as it is not used within an RMATCH()
+ loop. */
+
+#define Lstart_eptr F->temp_sptr[0]
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Lctype F->temp_32[2]
+#define Lpropvalue F->temp_32[3]
+
+ case OP_TYPEEXACT:
+ Lmin = Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATTYPE;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ reptype = (*Fecode == OP_TYPEMINUPTO)? REPTYPE_MIN : REPTYPE_MAX;
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATTYPE;
+
+ case OP_TYPEPOSSTAR:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = UINT32_MAX;
+ Fecode++;
+ goto REPEATTYPE;
+
+ case OP_TYPEPOSPLUS:
+ reptype = REPTYPE_POS;
+ Lmin = 1;
+ Lmax = UINT32_MAX;
+ Fecode++;
+ goto REPEATTYPE;
+
+ case OP_TYPEPOSQUERY:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = 1;
+ Fecode++;
+ goto REPEATTYPE;
+
+ case OP_TYPEPOSUPTO:
+ reptype = REPTYPE_POS;
+ Lmin = 0;
+ Lmax = GET2(Fecode, 1);
+ Fecode += 1 + IMM2_SIZE;
+ goto REPEATTYPE;
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ fc = *Fecode++ - OP_TYPESTAR;
+ Lmin = rep_min[fc];
+ Lmax = rep_max[fc];
+ reptype = rep_typ[fc];
+
+ /* Common code for all repeated character type matches. */
+
+ REPEATTYPE:
+ Lctype = *Fecode++; /* Code for the character type */
+
+#ifdef SUPPORT_UNICODE
+ if (Lctype == OP_PROP || Lctype == OP_NOTPROP)
+ {
+ proptype = *Fecode++;
+ Lpropvalue = *Fecode++;
+ }
+ else proptype = -1;
+#endif
+
+ /* First, ensure the minimum number of matches are present. Use inline
+ code for maximizing the speed, and do the type test once at the start
+ (i.e. keep it out of the loop). The code for UTF mode is separated out for
+ tidiness, except for Unicode property tests. */
+
+ if (Lmin > 0)
+ {
+#ifdef SUPPORT_UNICODE
+ if (proptype >= 0) /* Property tests in all modes */
+ {
+ switch(proptype)
+ {
+ case PT_ANY:
+ if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ }
+ break;
+
+ case PT_LAMP:
+ for (i = 1; i <= Lmin; i++)
+ {
+ int chartype;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ chartype = UCD_CHARTYPE(fc);
+ if ((chartype == ucp_Lu ||
+ chartype == ucp_Ll ||
+ chartype == ucp_Lt) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case PT_GC:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case PT_PC:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case PT_SC:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case PT_ALNUM:
+ for (i = 1; i <= Lmin; i++)
+ {
+ int category;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ category = UCD_CATEGORY(fc);
+ if ((category == ucp_L || category == ucp_N) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ break;
+
+ default:
+ if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ break;
+
+ case PT_WORD:
+ for (i = 1; i <= Lmin; i++)
+ {
+ int category;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ category = UCD_CATEGORY(fc);
+ if ((category == ucp_L || category == ucp_N ||
+ fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case PT_CLIST:
+ for (i = 1; i <= Lmin; i++)
+ {
+ const uint32_t *cp;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+ for (;;)
+ {
+ if (fc < *cp)
+ {
+ if (Lctype == OP_NOTPROP) break;
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (fc == *cp++)
+ {
+ if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ }
+ break;
+
+ case PT_UCNC:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+ fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+ fc >= 0xe000) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ /* This should not occur */
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+ }
+
+ /* Match extended Unicode sequences. We will get here only if the
+ support is in the binary; otherwise a compile-time error occurs. */
+
+ else if (Lctype == OP_EXTUNI)
+ {
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+ Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject,
+ mb->end_subject, utf, NULL);
+ }
+ CHECK_PARTIAL();
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+/* Handle all other cases in UTF mode */
+
+#ifdef SUPPORT_UNICODE
+ if (utf) switch(Lctype)
+ {
+ case OP_ANY:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+ if (mb->partial != 0 &&
+ Feptr + 1 >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ UCHAR21(Feptr) == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ Feptr++;
+ ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+ }
+ break;
+
+ case OP_ALLANY:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ Feptr++;
+ ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+ }
+ break;
+
+ case OP_ANYBYTE:
+ if (Feptr > mb->end_subject - Lmin) RRETURN(MATCH_NOMATCH);
+ Feptr += Lmin;
+ break;
+
+ case OP_ANYNL:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ switch(fc)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+
+ case CHAR_CR:
+ if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++;
+ break;
+
+ case CHAR_LF:
+ break;
+
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ switch(fc)
+ {
+ HSPACE_CASES: RRETURN(MATCH_NOMATCH);
+ default: break;
+ }
+ }
+ break;
+
+ case OP_HSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ switch(fc)
+ {
+ HSPACE_CASES: break;
+ default: RRETURN(MATCH_NOMATCH);
+ }
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ switch(fc)
+ {
+ VSPACE_CASES: RRETURN(MATCH_NOMATCH);
+ default: break;
+ }
+ }
+ break;
+
+ case OP_VSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ switch(fc)
+ {
+ VSPACE_CASES: break;
+ default: RRETURN(MATCH_NOMATCH);
+ }
+ }
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINC(fc, Feptr);
+ if (fc < 128 && (mb->ctypes[fc] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = 1; i <= Lmin; i++)
+ {
+ uint32_t cc;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21(Feptr);
+ if (cc >= 128 || (mb->ctypes[cc] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ /* No need to skip more code units - we know it has only one. */
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ uint32_t cc;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21(Feptr);
+ if (cc < 128 && (mb->ctypes[cc] & ctype_space) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ uint32_t cc;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21(Feptr);
+ if (cc >= 128 || (mb->ctypes[cc] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ /* No need to skip more code units - we know it has only one. */
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = 1; i <= Lmin; i++)
+ {
+ uint32_t cc;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21(Feptr);
+ if (cc < 128 && (mb->ctypes[cc] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = 1; i <= Lmin; i++)
+ {
+ uint32_t cc;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ cc = UCHAR21(Feptr);
+ if (cc >= 128 || (mb->ctypes[cc] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ /* No need to skip more code units - we know it has only one. */
+ }
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ } /* End switch(Lctype) */
+
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Code for the non-UTF case for minimum matching of operators other
+ than OP_PROP and OP_NOTPROP. */
+
+ switch(Lctype)
+ {
+ case OP_ANY:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+ if (mb->partial != 0 &&
+ Feptr + 1 >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ *Feptr == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ Feptr++;
+ }
+ break;
+
+ case OP_ALLANY:
+ if (Feptr > mb->end_subject - Lmin)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ Feptr += Lmin;
+ break;
+
+ /* This OP_ANYBYTE case will never be reached because \C gets turned
+ into OP_ALLANY in non-UTF mode. Cut out the code so that coverage
+ reports don't complain about it's never being used. */
+
+/* case OP_ANYBYTE:
+* if (Feptr > mb->end_subject - Lmin)
+* {
+* SCHECK_PARTIAL();
+* RRETURN(MATCH_NOMATCH);
+* }
+* Feptr += Lmin;
+* break;
+*/
+ case OP_ANYNL:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ switch(*Feptr++)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+
+ case CHAR_CR:
+ if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++;
+ break;
+
+ case CHAR_LF:
+ break;
+
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ case 0x2028:
+ case 0x2029:
+#endif
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ switch(*Feptr++)
+ {
+ default: break;
+ HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ HSPACE_MULTIBYTE_CASES:
+#endif
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ break;
+
+ case OP_HSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ switch(*Feptr++)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+ HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ HSPACE_MULTIBYTE_CASES:
+#endif
+ break;
+ }
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ switch(*Feptr++)
+ {
+ VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ VSPACE_MULTIBYTE_CASES:
+#endif
+ RRETURN(MATCH_NOMATCH);
+ default: break;
+ }
+ }
+ break;
+
+ case OP_VSPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ switch(*Feptr++)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+ VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ VSPACE_MULTIBYTE_CASES:
+#endif
+ break;
+ }
+ }
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = 1; i <= Lmin; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ Feptr++;
+ }
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+ }
+
+ /* If Lmin = Lmax we are done. Continue with the main loop. */
+
+ if (Lmin == Lmax) continue;
+
+ /* If minimizing, we have to test the rest of the pattern before each
+ subsequent match. */
+
+ if (reptype == REPTYPE_MIN)
+ {
+#ifdef SUPPORT_UNICODE
+ if (proptype >= 0)
+ {
+ switch(proptype)
+ {
+ case PT_ANY:
+ for (;;)
+ {
+ RMATCH(Fecode, RM208);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ case PT_LAMP:
+ for (;;)
+ {
+ int chartype;
+ RMATCH(Fecode, RM209);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ chartype = UCD_CHARTYPE(fc);
+ if ((chartype == ucp_Lu ||
+ chartype == ucp_Ll ||
+ chartype == ucp_Lt) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ case PT_GC:
+ for (;;)
+ {
+ RMATCH(Fecode, RM210);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ case PT_PC:
+ for (;;)
+ {
+ RMATCH(Fecode, RM211);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ case PT_SC:
+ for (;;)
+ {
+ RMATCH(Fecode, RM212);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ case PT_ALNUM:
+ for (;;)
+ {
+ int category;
+ RMATCH(Fecode, RM213);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ category = UCD_CATEGORY(fc);
+ if ((category == ucp_L || category == ucp_N) ==
+ (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ for (;;)
+ {
+ RMATCH(Fecode, RM214);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ switch(fc)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ break;
+
+ default:
+ if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ /* Control never gets here */
+
+ case PT_WORD:
+ for (;;)
+ {
+ int category;
+ RMATCH(Fecode, RM215);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ category = UCD_CATEGORY(fc);
+ if ((category == ucp_L ||
+ category == ucp_N ||
+ fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ case PT_CLIST:
+ for (;;)
+ {
+ const uint32_t *cp;
+ RMATCH(Fecode, RM216);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+ for (;;)
+ {
+ if (fc < *cp)
+ {
+ if (Lctype == OP_NOTPROP) break;
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (fc == *cp++)
+ {
+ if (Lctype == OP_NOTPROP) RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ }
+ }
+ /* Control never gets here */
+
+ case PT_UCNC:
+ for (;;)
+ {
+ RMATCH(Fecode, RM217);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ GETCHARINCTEST(fc, Feptr);
+ if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+ fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+ fc >= 0xe000) == (Lctype == OP_NOTPROP))
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+ /* This should never occur */
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+ }
+
+ /* Match extended Unicode sequences. We will get here only if the
+ support is in the binary; otherwise a compile-time error occurs. */
+
+ else if (Lctype == OP_EXTUNI)
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM218);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+ Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+ utf, NULL);
+ }
+ CHECK_PARTIAL();
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* UTF mode for non-property testing character types. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM219);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lctype == OP_ANY && IS_NEWLINE(Feptr)) RRETURN(MATCH_NOMATCH);
+ GETCHARINC(fc, Feptr);
+ switch(Lctype)
+ {
+ case OP_ANY: /* This is the non-NL case */
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ Feptr >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ fc == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ break;
+
+ case OP_ALLANY:
+ case OP_ANYBYTE:
+ break;
+
+ case OP_ANYNL:
+ switch(fc)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+
+ case CHAR_CR:
+ if (Feptr < mb->end_subject && UCHAR21(Feptr) == CHAR_LF) Feptr++;
+ break;
+
+ case CHAR_LF:
+ break;
+
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#ifndef EBCDIC
+ case 0x2028:
+ case 0x2029:
+#endif /* Not EBCDIC */
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF)
+ RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ switch(fc)
+ {
+ HSPACE_CASES: RRETURN(MATCH_NOMATCH);
+ default: break;
+ }
+ break;
+
+ case OP_HSPACE:
+ switch(fc)
+ {
+ HSPACE_CASES: break;
+ default: RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ switch(fc)
+ {
+ VSPACE_CASES: RRETURN(MATCH_NOMATCH);
+ default: break;
+ }
+ break;
+
+ case OP_VSPACE:
+ switch(fc)
+ {
+ VSPACE_CASES: break;
+ default: RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case OP_NOT_DIGIT:
+ if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_DIGIT:
+ if (fc >= 256 || (mb->ctypes[fc] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WHITESPACE:
+ if (fc >= 256 || (mb->ctypes[fc] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WORDCHAR:
+ if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF mode */
+ {
+ for (;;)
+ {
+ RMATCH(Fecode, RM33);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ if (Lctype == OP_ANY && IS_NEWLINE(Feptr))
+ RRETURN(MATCH_NOMATCH);
+ fc = *Feptr++;
+ switch(Lctype)
+ {
+ case OP_ANY: /* This is the non-NL case */
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ Feptr >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ fc == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ break;
+
+ case OP_ALLANY:
+ case OP_ANYBYTE:
+ break;
+
+ case OP_ANYNL:
+ switch(fc)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+
+ case CHAR_CR:
+ if (Feptr < mb->end_subject && *Feptr == CHAR_LF) Feptr++;
+ break;
+
+ case CHAR_LF:
+ break;
+
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_NEL:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ case 0x2028:
+ case 0x2029:
+#endif
+ if (mb->bsr_convention == PCRE2_BSR_ANYCRLF)
+ RRETURN(MATCH_NOMATCH);
+ break;
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ switch(fc)
+ {
+ default: break;
+ HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ HSPACE_MULTIBYTE_CASES:
+#endif
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case OP_HSPACE:
+ switch(fc)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+ HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ HSPACE_MULTIBYTE_CASES:
+#endif
+ break;
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ switch(fc)
+ {
+ default: break;
+ VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ VSPACE_MULTIBYTE_CASES:
+#endif
+ RRETURN(MATCH_NOMATCH);
+ }
+ break;
+
+ case OP_VSPACE:
+ switch(fc)
+ {
+ default: RRETURN(MATCH_NOMATCH);
+ VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ VSPACE_MULTIBYTE_CASES:
+#endif
+ break;
+ }
+ break;
+
+ case OP_NOT_DIGIT:
+ if (MAX_255(fc) && (mb->ctypes[fc] & ctype_digit) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_DIGIT:
+ if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_digit) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ if (MAX_255(fc) && (mb->ctypes[fc] & ctype_space) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WHITESPACE:
+ if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_space) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ if (MAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ case OP_WORDCHAR:
+ if (!MAX_255(fc) || (mb->ctypes[fc] & ctype_word) == 0)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+ }
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, it is worth using inline code for speed, doing the type
+ test once at the start (i.e. keep it out of the loop). */
+
+ else
+ {
+ Lstart_eptr = Feptr; /* Remember where we started */
+
+#ifdef SUPPORT_UNICODE
+ if (proptype >= 0)
+ {
+ switch(proptype)
+ {
+ case PT_ANY:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ if (Lctype == OP_NOTPROP) break;
+ Feptr+= len;
+ }
+ break;
+
+ case PT_LAMP:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int chartype;
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ chartype = UCD_CHARTYPE(fc);
+ if ((chartype == ucp_Lu ||
+ chartype == ucp_Ll ||
+ chartype == ucp_Lt) == (Lctype == OP_NOTPROP))
+ break;
+ Feptr+= len;
+ }
+ break;
+
+ case PT_GC:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ if ((UCD_CATEGORY(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ break;
+ Feptr+= len;
+ }
+ break;
+
+ case PT_PC:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ if ((UCD_CHARTYPE(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ break;
+ Feptr+= len;
+ }
+ break;
+
+ case PT_SC:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ if ((UCD_SCRIPT(fc) == Lpropvalue) == (Lctype == OP_NOTPROP))
+ break;
+ Feptr+= len;
+ }
+ break;
+
+ case PT_ALNUM:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int category;
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ category = UCD_CATEGORY(fc);
+ if ((category == ucp_L || category == ucp_N) ==
+ (Lctype == OP_NOTPROP))
+ break;
+ Feptr+= len;
+ }
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ switch(fc)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ if (Lctype == OP_NOTPROP) goto ENDLOOP99; /* Break the loop */
+ break;
+
+ default:
+ if ((UCD_CATEGORY(fc) == ucp_Z) == (Lctype == OP_NOTPROP))
+ goto ENDLOOP99; /* Break the loop */
+ break;
+ }
+ Feptr+= len;
+ }
+ ENDLOOP99:
+ break;
+
+ case PT_WORD:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int category;
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ category = UCD_CATEGORY(fc);
+ if ((category == ucp_L || category == ucp_N ||
+ fc == CHAR_UNDERSCORE) == (Lctype == OP_NOTPROP))
+ break;
+ Feptr+= len;
+ }
+ break;
+
+ case PT_CLIST:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ const uint32_t *cp;
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ cp = PRIV(ucd_caseless_sets) + Lpropvalue;
+ for (;;)
+ {
+ if (fc < *cp)
+ { if (Lctype == OP_NOTPROP) break; else goto GOT_MAX; }
+ if (fc == *cp++)
+ { if (Lctype == OP_NOTPROP) goto GOT_MAX; else break; }
+ }
+ Feptr += len;
+ }
+ GOT_MAX:
+ break;
+
+ case PT_UCNC:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLENTEST(fc, Feptr, len);
+ if ((fc == CHAR_DOLLAR_SIGN || fc == CHAR_COMMERCIAL_AT ||
+ fc == CHAR_GRAVE_ACCENT || (fc >= 0xa0 && fc <= 0xd7ff) ||
+ fc >= 0xe000) == (Lctype == OP_NOTPROP))
+ break;
+ Feptr += len;
+ }
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+
+ /* Feptr is now past the end of the maximum run */
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't
+ go too far. */
+
+ for(;;)
+ {
+ if (Feptr <= Lstart_eptr) break;
+ RMATCH(Fecode, RM222);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ if (utf) BACKCHAR(Feptr);
+ }
+ }
+
+ /* Match extended Unicode grapheme clusters. We will get here only if the
+ support is in the binary; otherwise a compile-time error occurs. */
+
+ else if (Lctype == OP_EXTUNI)
+ {
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ else
+ {
+ GETCHARINCTEST(fc, Feptr);
+ Feptr = PRIV(extuni)(fc, Feptr, mb->start_subject, mb->end_subject,
+ utf, NULL);
+ }
+ CHECK_PARTIAL();
+ }
+
+ /* Feptr is now past the end of the maximum run */
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ /* We use <= Lstart_eptr rather than == Lstart_eptr to detect the start
+ of the run while backtracking because the use of \C in UTF mode can
+ cause BACKCHAR to move back past Lstart_eptr. This is just palliative;
+ the use of \C in UTF mode is fraught with danger. */
+
+ for(;;)
+ {
+ int lgb, rgb;
+ PCRE2_SPTR fptr;
+
+ if (Feptr <= Lstart_eptr) break; /* At start of char run */
+ RMATCH(Fecode, RM220);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+
+ /* Backtracking over an extended grapheme cluster involves inspecting
+ the previous two characters (if present) to see if a break is
+ permitted between them. */
+
+ Feptr--;
+ if (!utf) fc = *Feptr; else
+ {
+ BACKCHAR(Feptr);
+ GETCHAR(fc, Feptr);
+ }
+ rgb = UCD_GRAPHBREAK(fc);
+
+ for (;;)
+ {
+ if (Feptr <= Lstart_eptr) break; /* At start of char run */
+ fptr = Feptr - 1;
+ if (!utf) fc = *fptr; else
+ {
+ BACKCHAR(fptr);
+ GETCHAR(fc, fptr);
+ }
+ lgb = UCD_GRAPHBREAK(fc);
+ if ((PRIV(ucp_gbtable)[lgb] & (1 << rgb)) == 0) break;
+ Feptr = fptr;
+ rgb = lgb;
+ }
+ }
+ }
+
+ else
+#endif /* SUPPORT_UNICODE */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ switch(Lctype)
+ {
+ case OP_ANY:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (IS_NEWLINE(Feptr)) break;
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ Feptr + 1 >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ UCHAR21(Feptr) == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ Feptr++;
+ ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+ }
+ break;
+
+ case OP_ALLANY:
+ if (Lmax < UINT32_MAX)
+ {
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ Feptr++;
+ ACROSSCHAR(Feptr < mb->end_subject, Feptr, Feptr++);
+ }
+ }
+ else
+ {
+ Feptr = mb->end_subject; /* Unlimited UTF-8 repeat */
+ SCHECK_PARTIAL();
+ }
+ break;
+
+ /* The "byte" (i.e. "code unit") case is the same as non-UTF */
+
+ case OP_ANYBYTE:
+ fc = Lmax - Lmin;
+ if (fc > (uint32_t)(mb->end_subject - Feptr))
+ {
+ Feptr = mb->end_subject;
+ SCHECK_PARTIAL();
+ }
+ else Feptr += fc;
+ break;
+
+ case OP_ANYNL:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc == CHAR_CR)
+ {
+ if (++Feptr >= mb->end_subject) break;
+ if (UCHAR21(Feptr) == CHAR_LF) Feptr++;
+ }
+ else
+ {
+ if (fc != CHAR_LF &&
+ (mb->bsr_convention == PCRE2_BSR_ANYCRLF ||
+ (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL
+#ifndef EBCDIC
+ && fc != 0x2028 && fc != 0x2029
+#endif /* Not EBCDIC */
+ )))
+ break;
+ Feptr += len;
+ }
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ case OP_HSPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ BOOL gotspace;
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ switch(fc)
+ {
+ HSPACE_CASES: gotspace = TRUE; break;
+ default: gotspace = FALSE; break;
+ }
+ if (gotspace == (Lctype == OP_NOT_HSPACE)) break;
+ Feptr += len;
+ }
+ break;
+
+ case OP_NOT_VSPACE:
+ case OP_VSPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ BOOL gotspace;
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ switch(fc)
+ {
+ VSPACE_CASES: gotspace = TRUE; break;
+ default: gotspace = FALSE; break;
+ }
+ if (gotspace == (Lctype == OP_NOT_VSPACE)) break;
+ Feptr += len;
+ }
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc < 256 && (mb->ctypes[fc] & ctype_digit) != 0) break;
+ Feptr+= len;
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc >= 256 ||(mb->ctypes[fc] & ctype_digit) == 0) break;
+ Feptr+= len;
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc < 256 && (mb->ctypes[fc] & ctype_space) != 0) break;
+ Feptr+= len;
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc >= 256 ||(mb->ctypes[fc] & ctype_space) == 0) break;
+ Feptr+= len;
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc < 256 && (mb->ctypes[fc] & ctype_word) != 0) break;
+ Feptr+= len;
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ int len = 1;
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ GETCHARLEN(fc, Feptr, len);
+ if (fc >= 256 || (mb->ctypes[fc] & ctype_word) == 0) break;
+ Feptr+= len;
+ }
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ /* After \C in UTF mode, Lstart_eptr might be in the middle of a
+ Unicode character. Use <= Lstart_eptr to ensure backtracking doesn't go
+ too far. */
+
+ for(;;)
+ {
+ if (Feptr <= Lstart_eptr) break;
+ RMATCH(Fecode, RM221);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ BACKCHAR(Feptr);
+ if (Lctype == OP_ANYNL && Feptr > Lstart_eptr &&
+ UCHAR21(Feptr) == CHAR_NL && UCHAR21(Feptr - 1) == CHAR_CR)
+ Feptr--;
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF mode */
+ {
+ switch(Lctype)
+ {
+ case OP_ANY:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (IS_NEWLINE(Feptr)) break;
+ if (mb->partial != 0 && /* Take care with CRLF partial */
+ Feptr + 1 >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ *Feptr == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ Feptr++;
+ }
+ break;
+
+ case OP_ALLANY:
+ case OP_ANYBYTE:
+ fc = Lmax - Lmin;
+ if (fc > (uint32_t)(mb->end_subject - Feptr))
+ {
+ Feptr = mb->end_subject;
+ SCHECK_PARTIAL();
+ }
+ else Feptr += fc;
+ break;
+
+ case OP_ANYNL:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ fc = *Feptr;
+ if (fc == CHAR_CR)
+ {
+ if (++Feptr >= mb->end_subject) break;
+ if (*Feptr == CHAR_LF) Feptr++;
+ }
+ else
+ {
+ if (fc != CHAR_LF && (mb->bsr_convention == PCRE2_BSR_ANYCRLF ||
+ (fc != CHAR_VT && fc != CHAR_FF && fc != CHAR_NEL
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ && fc != 0x2028 && fc != 0x2029
+#endif
+ ))) break;
+ Feptr++;
+ }
+ }
+ break;
+
+ case OP_NOT_HSPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ switch(*Feptr)
+ {
+ default: Feptr++; break;
+ HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ HSPACE_MULTIBYTE_CASES:
+#endif
+ goto ENDLOOP00;
+ }
+ }
+ ENDLOOP00:
+ break;
+
+ case OP_HSPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ switch(*Feptr)
+ {
+ default: goto ENDLOOP01;
+ HSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ HSPACE_MULTIBYTE_CASES:
+#endif
+ Feptr++; break;
+ }
+ }
+ ENDLOOP01:
+ break;
+
+ case OP_NOT_VSPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ switch(*Feptr)
+ {
+ default: Feptr++; break;
+ VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ VSPACE_MULTIBYTE_CASES:
+#endif
+ goto ENDLOOP02;
+ }
+ }
+ ENDLOOP02:
+ break;
+
+ case OP_VSPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ switch(*Feptr)
+ {
+ default: goto ENDLOOP03;
+ VSPACE_BYTE_CASES:
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ VSPACE_MULTIBYTE_CASES:
+#endif
+ Feptr++; break;
+ }
+ }
+ ENDLOOP03:
+ break;
+
+ case OP_NOT_DIGIT:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_digit) != 0)
+ break;
+ Feptr++;
+ }
+ break;
+
+ case OP_DIGIT:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_digit) == 0)
+ break;
+ Feptr++;
+ }
+ break;
+
+ case OP_NOT_WHITESPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_space) != 0)
+ break;
+ Feptr++;
+ }
+ break;
+
+ case OP_WHITESPACE:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_space) == 0)
+ break;
+ Feptr++;
+ }
+ break;
+
+ case OP_NOT_WORDCHAR:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (MAX_255(*Feptr) && (mb->ctypes[*Feptr] & ctype_word) != 0)
+ break;
+ Feptr++;
+ }
+ break;
+
+ case OP_WORDCHAR:
+ for (i = Lmin; i < Lmax; i++)
+ {
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ break;
+ }
+ if (!MAX_255(*Feptr) || (mb->ctypes[*Feptr] & ctype_word) == 0)
+ break;
+ Feptr++;
+ }
+ break;
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+
+ if (reptype == REPTYPE_POS) continue; /* No backtracking */
+
+ for (;;)
+ {
+ if (Feptr == Lstart_eptr) break;
+ RMATCH(Fecode, RM34);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr--;
+ if (Lctype == OP_ANYNL && Feptr > Lstart_eptr && *Feptr == CHAR_LF &&
+ Feptr[-1] == CHAR_CR) Feptr--;
+ }
+ }
+ }
+ break; /* End of repeat character type processing */
+
+#undef Lstart_eptr
+#undef Lmin
+#undef Lmax
+#undef Lctype
+#undef Lpropvalue
+
+
+ /* ===================================================================== */
+ /* Match a back reference, possibly repeatedly. Look past the end of the
+ item to see if there is repeat information following. The OP_REF and
+ OP_REFI opcodes are used for a reference to a numbered group or to a
+ non-duplicated named group. For a duplicated named group, OP_DNREF and
+ OP_DNREFI are used. In this case we must scan the list of groups to which
+ the name refers, and use the first one that is set. */
+
+#define Lmin F->temp_32[0]
+#define Lmax F->temp_32[1]
+#define Lcaseless F->temp_32[2]
+#define Lstart F->temp_sptr[0]
+#define Loffset F->temp_size
+
+ case OP_DNREF:
+ case OP_DNREFI:
+ Lcaseless = (Fop == OP_DNREFI);
+ {
+ int count = GET2(Fecode, 1+IMM2_SIZE);
+ PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size;
+ Fecode += 1 + 2*IMM2_SIZE;
+
+ while (count-- > 0)
+ {
+ Loffset = (GET2(slot, 0) << 1) - 2;
+ if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET) break;
+ slot += mb->name_entry_size;
+ }
+ }
+ goto REF_REPEAT;
+
+ case OP_REF:
+ case OP_REFI:
+ Lcaseless = (Fop == OP_REFI);
+ Loffset = (GET2(Fecode, 1) << 1) - 2;
+ Fecode += 1 + IMM2_SIZE;
+
+ /* Set up for repetition, or handle the non-repeated case. The maximum and
+ minimum must be in the heap frame, but as they are short-term values, we
+ use temporary fields. */
+
+ REF_REPEAT:
+ switch (*Fecode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ fc = *Fecode++ - OP_CRSTAR;
+ Lmin = rep_min[fc];
+ Lmax = rep_max[fc];
+ reptype = rep_typ[fc];
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ Lmin = GET2(Fecode, 1);
+ Lmax = GET2(Fecode, 1 + IMM2_SIZE);
+ reptype = rep_typ[*Fecode - OP_CRSTAR];
+ if (Lmax == 0) Lmax = UINT32_MAX; /* Max 0 => infinity */
+ Fecode += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default: /* No repeat follows */
+ {
+ rrc = match_ref(Loffset, Lcaseless, F, mb, &length);
+ if (rrc != 0)
+ {
+ if (rrc > 0) Feptr = mb->end_subject; /* Partial match */
+ CHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ Feptr += length;
+ continue; /* With the main loop */
+ }
+
+ /* Handle repeated back references. If a set group has length zero, just
+ continue with the main loop, because it matches however many times. For an
+ unset reference, if the minimum is zero, we can also just continue. We can
+ also continue if PCRE2_MATCH_UNSET_BACKREF is set, because this makes unset
+ group behave as a zero-length group. For any other unset cases, carrying
+ on will result in NOMATCH. */
+
+ if (Loffset < Foffset_top && Fovector[Loffset] != PCRE2_UNSET)
+ {
+ if (Fovector[Loffset] == Fovector[Loffset + 1]) continue;
+ }
+ else /* Group is not set */
+ {
+ if (Lmin == 0 || (mb->poptions & PCRE2_MATCH_UNSET_BACKREF) != 0)
+ continue;
+ }
+
+ /* First, ensure the minimum number of matches are present. */
+
+ for (i = 1; i <= Lmin; i++)
+ {
+ PCRE2_SIZE slength;
+ rrc = match_ref(Loffset, Lcaseless, F, mb, &slength);
+ if (rrc != 0)
+ {
+ if (rrc > 0) Feptr = mb->end_subject; /* Partial match */
+ CHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ Feptr += slength;
+ }
+
+ /* If min = max, we are done. They are not both allowed to be zero. */
+
+ if (Lmin == Lmax) continue;
+
+ /* If minimizing, keep trying and advancing the pointer. */
+
+ if (reptype == REPTYPE_MIN)
+ {
+ for (;;)
+ {
+ PCRE2_SIZE slength;
+ RMATCH(Fecode, RM20);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Lmin++ >= Lmax) RRETURN(MATCH_NOMATCH);
+ rrc = match_ref(Loffset, Lcaseless, F, mb, &slength);
+ if (rrc != 0)
+ {
+ if (rrc > 0) Feptr = mb->end_subject; /* Partial match */
+ CHECK_PARTIAL();
+ RRETURN(MATCH_NOMATCH);
+ }
+ Feptr += slength;
+ }
+ /* Control never gets here */
+ }
+
+ /* If maximizing, find the longest string and work backwards, as long as
+ the matched lengths for each iteration are the same. */
+
+ else
+ {
+ BOOL samelengths = TRUE;
+ Lstart = Feptr; /* Starting position */
+ Flength = Fovector[Loffset+1] - Fovector[Loffset];
+
+ for (i = Lmin; i < Lmax; i++)
+ {
+ PCRE2_SIZE slength;
+ rrc = match_ref(Loffset, Lcaseless, F, mb, &slength);
+ if (rrc != 0)
+ {
+ /* Can't use CHECK_PARTIAL because we don't want to update Feptr in
+ the soft partial matching case. */
+
+ if (rrc > 0 && mb->partial != 0 &&
+ mb->end_subject > mb->start_used_ptr)
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ break;
+ }
+
+ if (slength != Flength) samelengths = FALSE;
+ Feptr += slength;
+ }
+
+ /* If the length matched for each repetition is the same as the length of
+ the captured group, we can easily work backwards. This is the normal
+ case. However, in caseless UTF-8 mode there are pairs of case-equivalent
+ characters whose lengths (in terms of code units) differ. However, this
+ is very rare, so we handle it by re-matching fewer and fewer times. */
+
+ if (samelengths)
+ {
+ while (Feptr >= Lstart)
+ {
+ RMATCH(Fecode, RM21);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Feptr -= Flength;
+ }
+ }
+
+ /* The rare case of non-matching lengths. Re-scan the repetition for each
+ iteration. We know that match_ref() will succeed every time. */
+
+ else
+ {
+ Lmax = i;
+ for (;;)
+ {
+ RMATCH(Fecode, RM22);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ if (Feptr == Lstart) break; /* Failed after minimal repetition */
+ Feptr = Lstart;
+ Lmax--;
+ for (i = Lmin; i < Lmax; i++)
+ {
+ PCRE2_SIZE slength;
+ (void)match_ref(Loffset, Lcaseless, F, mb, &slength);
+ Feptr += slength;
+ }
+ }
+ }
+
+ RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never gets here */
+
+#undef Lcaseless
+#undef Lmin
+#undef Lmax
+#undef Lstart
+#undef Loffset
+
+
+
+/* ========================================================================= */
+/* Opcodes for the start of various parenthesized items */
+/* ========================================================================= */
+
+ /* In all cases, if the result of RMATCH() is MATCH_THEN, check whether the
+ (*THEN) is within the current branch by comparing the address of OP_THEN
+ that is passed back with the end of the branch. If (*THEN) is within the
+ current branch, and the branch is one of two or more alternatives (it
+ either starts or ends with OP_ALT), we have reached the limit of THEN's
+ action, so convert the return code to NOMATCH, which will cause normal
+ backtracking to happen from now on. Otherwise, THEN is passed back to an
+ outer alternative. This implements Perl's treatment of parenthesized
+ groups, where a group not containing | does not affect the current
+ alternative, that is, (X) is NOT the same as (X|(*F)). */
+
+
+ /* ===================================================================== */
+ /* BRAZERO, BRAMINZERO and SKIPZERO occur just before a non-possessive
+ bracket group, indicating that it may occur zero times. It may repeat
+ infinitely, or not at all - i.e. it could be ()* or ()? or even (){0} in
+ the pattern. Brackets with fixed upper repeat limits are compiled as a
+ number of copies, with the optional ones preceded by BRAZERO or BRAMINZERO.
+ Possessive groups with possible zero repeats are preceded by BRAPOSZERO. */
+
+#define Lnext_ecode F->temp_sptr[0]
+
+ case OP_BRAZERO:
+ Lnext_ecode = Fecode + 1;
+ RMATCH(Lnext_ecode, RM9);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT);
+ Fecode = Lnext_ecode + 1 + LINK_SIZE;
+ break;
+
+ case OP_BRAMINZERO:
+ Lnext_ecode = Fecode + 1;
+ do Lnext_ecode += GET(Lnext_ecode, 1); while (*Lnext_ecode == OP_ALT);
+ RMATCH(Lnext_ecode + 1 + LINK_SIZE, RM10);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Fecode++;
+ break;
+
+#undef Lnext_ecode
+
+ case OP_SKIPZERO:
+ Fecode++;
+ do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT);
+ Fecode += 1 + LINK_SIZE;
+ break;
+
+
+ /* ===================================================================== */
+ /* Handle possessive brackets with an unlimited repeat. The end of these
+ brackets will always be OP_KETRPOS, which returns MATCH_KETRPOS without
+ going further in the pattern. */
+
+#define Lframe_type F->temp_32[0]
+#define Lmatched_once F->temp_32[1]
+#define Lzero_allowed F->temp_32[2]
+#define Lstart_eptr F->temp_sptr[0]
+#define Lstart_group F->temp_sptr[1]
+
+ case OP_BRAPOSZERO:
+ Lzero_allowed = TRUE; /* Zero repeat is allowed */
+ Fecode += 1;
+ if (*Fecode == OP_CBRAPOS || *Fecode == OP_SCBRAPOS)
+ goto POSSESSIVE_CAPTURE;
+ goto POSSESSIVE_NON_CAPTURE;
+
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ Lzero_allowed = FALSE; /* Zero repeat not allowed */
+
+ POSSESSIVE_NON_CAPTURE:
+ Lframe_type = GF_NOCAPTURE; /* Remembered frame type */
+ goto POSSESSIVE_GROUP;
+
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ Lzero_allowed = FALSE; /* Zero repeat not allowed */
+
+ POSSESSIVE_CAPTURE:
+ number = GET2(Fecode, 1+LINK_SIZE);
+ Lframe_type = GF_CAPTURE | number; /* Remembered frame type */
+
+ POSSESSIVE_GROUP:
+ Lmatched_once = FALSE; /* Never matched */
+ Lstart_group = Fecode; /* Start of this group */
+
+ for (;;)
+ {
+ Lstart_eptr = Feptr; /* Position at group start */
+ group_frame_type = Lframe_type;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM8);
+ if (rrc == MATCH_KETRPOS)
+ {
+ Lmatched_once = TRUE; /* Matched at least once */
+ if (Feptr == Lstart_eptr) /* Empty match; skip to end */
+ {
+ do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+ break;
+ }
+
+ Fecode = Lstart_group;
+ continue;
+ }
+
+ /* See comment above about handling THEN. */
+
+ if (rrc == MATCH_THEN)
+ {
+ PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1);
+ if (mb->verb_ecode_ptr < next_ecode &&
+ (*Fecode == OP_ALT || *next_ecode == OP_ALT))
+ rrc = MATCH_NOMATCH;
+ }
+
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Fecode += GET(Fecode, 1);
+ if (*Fecode != OP_ALT) break;
+ }
+
+ /* Success if matched something or zero repeat allowed */
+
+ if (Lmatched_once || Lzero_allowed)
+ {
+ Fecode += 1 + LINK_SIZE;
+ break;
+ }
+
+ RRETURN(MATCH_NOMATCH);
+
+#undef Lmatched_once
+#undef Lzero_allowed
+#undef Lframe_type
+#undef Lstart_eptr
+#undef Lstart_group
+
+
+ /* ===================================================================== */
+ /* Handle non-capturing brackets that cannot match an empty string. When we
+ get to the final alternative within the brackets, as long as there are no
+ THEN's in the pattern, we can optimize by not recording a new backtracking
+ point. (Ideally we should test for a THEN within this group, but we don't
+ have that information.) Don't do this if we are at the very top level,
+ however, because that would make handling assertions and once-only brackets
+ messier when there is nothing to go back to. */
+
+#define Lframe_type F->temp_32[0] /* Set for all that use GROUPLOOP */
+#define Lnext_branch F->temp_sptr[0] /* Used only in OP_BRA handling */
+
+ case OP_BRA:
+ if (mb->hasthen || Frdepth == 0)
+ {
+ Lframe_type = 0;
+ goto GROUPLOOP;
+ }
+
+ for (;;)
+ {
+ Lnext_branch = Fecode + GET(Fecode, 1);
+ if (*Lnext_branch != OP_ALT) break;
+
+ /* This is never the final branch. We do not need to test for MATCH_THEN
+ here because this code is not used when there is a THEN in the pattern. */
+
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM1);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Fecode = Lnext_branch;
+ }
+
+ /* Hit the start of the final branch. Continue at this level. */
+
+ Fecode += PRIV(OP_lengths)[*Fecode];
+ break;
+
+#undef Lnext_branch
+
+
+ /* ===================================================================== */
+ /* Handle a capturing bracket, other than those that are possessive with an
+ unlimited repeat. */
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ Lframe_type = GF_CAPTURE | GET2(Fecode, 1+LINK_SIZE);
+ goto GROUPLOOP;
+
+
+ /* ===================================================================== */
+ /* Atomic groups and non-capturing brackets that can match an empty string
+ must record a backtracking point and also set up a chained frame. */
+
+ case OP_ONCE:
+ case OP_SBRA:
+ Lframe_type = GF_NOCAPTURE | Fop;
+
+ GROUPLOOP:
+ for (;;)
+ {
+ group_frame_type = Lframe_type;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM2);
+ if (rrc == MATCH_THEN)
+ {
+ PCRE2_SPTR next_ecode = Fecode + GET(Fecode,1);
+ if (mb->verb_ecode_ptr < next_ecode &&
+ (*Fecode == OP_ALT || *next_ecode == OP_ALT))
+ rrc = MATCH_NOMATCH;
+ }
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Fecode += GET(Fecode, 1);
+ if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never reaches here. */
+
+#undef Lframe_type
+
+
+ /* ===================================================================== */
+ /* Recursion either matches the current regex, or some subexpression. The
+ offset data is the offset to the starting bracket from the start of the
+ whole pattern. (This is so that it works from duplicated subpatterns.) */
+
+#define Lframe_type F->temp_32[0]
+#define Lstart_branch F->temp_sptr[0]
+
+ case OP_RECURSE:
+ bracode = mb->start_code + GET(Fecode, 1);
+ number = (bracode == mb->start_code)? 0 : GET2(bracode, 1 + LINK_SIZE);
+
+ /* If we are already in a recursion, check for repeating the same one
+ without advancing the subject pointer. This should catch convoluted mutual
+ recursions. (Some simple cases are caught at compile time.) */
+
+ if (Fcurrent_recurse != RECURSE_UNSET)
+ {
+ offset = Flast_group_offset;
+ while (offset != PCRE2_UNSET)
+ {
+ N = (heapframe *)((char *)mb->match_frames + offset);
+ P = (heapframe *)((char *)N - frame_size);
+ if (N->group_frame_type == (GF_RECURSE | number))
+ {
+ if (Feptr == P->eptr) return PCRE2_ERROR_RECURSELOOP;
+ break;
+ }
+ offset = P->last_group_offset;
+ }
+ }
+
+ /* Now run the recursion, branch by branch. */
+
+ Lstart_branch = bracode;
+ Lframe_type = GF_RECURSE | number;
+
+ for (;;)
+ {
+ PCRE2_SPTR next_ecode;
+
+ group_frame_type = Lframe_type;
+ RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM11);
+ next_ecode = Lstart_branch + GET(Lstart_branch,1);
+
+ /* Handle backtracking verbs, which are defined in a range that can
+ easily be tested for. PCRE does not allow THEN, SKIP, PRUNE or COMMIT to
+ escape beyond a recursion; they cause a NOMATCH for the entire recursion.
+
+ When one of these verbs triggers, the current recursion group number is
+ recorded. If it matches the recursion we are processing, the verb
+ happened within the recursion and we must deal with it. Otherwise it must
+ have happened after the recursion completed, and so has to be passed
+ back. See comment above about handling THEN. */
+
+ if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX &&
+ mb->verb_current_recurse == (Lframe_type ^ GF_RECURSE))
+ {
+ if (rrc == MATCH_THEN && mb->verb_ecode_ptr < next_ecode &&
+ (*Lstart_branch == OP_ALT || *next_ecode == OP_ALT))
+ rrc = MATCH_NOMATCH;
+ else RRETURN(MATCH_NOMATCH);
+ }
+
+ /* Note that carrying on after (*ACCEPT) in a recursion is handled in the
+ OP_ACCEPT code. Nothing needs to be done here. */
+
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Lstart_branch = next_ecode;
+ if (*Lstart_branch != OP_ALT) RRETURN(MATCH_NOMATCH);
+ }
+ /* Control never reaches here. */
+
+#undef Lframe_type
+#undef Lstart_branch
+
+
+ /* ===================================================================== */
+ /* Positive assertions are like other groups except that PCRE doesn't allow
+ the effect of (*THEN) to escape beyond an assertion; it is therefore
+ treated as NOMATCH. (*ACCEPT) is treated as successful assertion, with its
+ captures and mark retained. Any other return is an error. */
+
+#define Lframe_type F->temp_32[0]
+
+ case OP_ASSERT:
+ case OP_ASSERTBACK:
+ Lframe_type = GF_NOCAPTURE | Fop;
+ for (;;)
+ {
+ group_frame_type = Lframe_type;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM3);
+ if (rrc == MATCH_ACCEPT)
+ {
+ memcpy(Fovector,
+ (char *)assert_accept_frame + offsetof(heapframe, ovector),
+ assert_accept_frame->offset_top * sizeof(PCRE2_SIZE));
+ Foffset_top = assert_accept_frame->offset_top;
+ Fmark = assert_accept_frame->mark;
+ break;
+ }
+ if (rrc != MATCH_NOMATCH && rrc != MATCH_THEN) RRETURN(rrc);
+ Fecode += GET(Fecode, 1);
+ if (*Fecode != OP_ALT) RRETURN(MATCH_NOMATCH);
+ }
+
+ do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+ Fecode += 1 + LINK_SIZE;
+ break;
+
+#undef Lframe_type
+
+
+ /* ===================================================================== */
+ /* Handle negative assertions. Loop for each non-matching branch as for
+ positive assertions. */
+
+#define Lframe_type F->temp_32[0]
+
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK_NOT:
+ Lframe_type = GF_NOCAPTURE | Fop;
+
+ for (;;)
+ {
+ group_frame_type = Lframe_type;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM4);
+ switch(rrc)
+ {
+ case MATCH_ACCEPT: /* Assertion matched, therefore it fails. */
+ case MATCH_MATCH:
+ RRETURN (MATCH_NOMATCH);
+
+ case MATCH_NOMATCH: /* Branch failed, try next if present. */
+ case MATCH_THEN:
+ Fecode += GET(Fecode, 1);
+ if (*Fecode != OP_ALT) goto ASSERT_NOT_FAILED;
+ break;
+
+ case MATCH_COMMIT: /* Assertion forced to fail, therefore continue. */
+ case MATCH_SKIP:
+ case MATCH_PRUNE:
+ do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+ goto ASSERT_NOT_FAILED;
+
+ default: /* Pass back any other return */
+ RRETURN(rrc);
+ }
+ }
+
+ /* None of the branches have matched or there was a backtrack to (*COMMIT),
+ (*SKIP), (*PRUNE), or (*THEN) in the last branch. This is success for a
+ negative assertion, so carry on. */
+
+ ASSERT_NOT_FAILED:
+ Fecode += 1 + LINK_SIZE;
+ break;
+
+#undef Lframe_type
+
+
+ /* ===================================================================== */
+ /* The callout item calls an external function, if one is provided, passing
+ details of the match so far. This is mainly for debugging, though the
+ function is able to force a failure. */
+
+ case OP_CALLOUT:
+ case OP_CALLOUT_STR:
+ rrc = do_callout(F, mb, &length);
+ if (rrc > 0) RRETURN(MATCH_NOMATCH);
+ if (rrc < 0) RRETURN(rrc);
+ Fecode += length;
+ break;
+
+
+ /* ===================================================================== */
+ /* Conditional group: compilation checked that there are no more than two
+ branches. If the condition is false, skipping the first branch takes us
+ past the end of the item if there is only one branch, but that's exactly
+ what we want. */
+
+ case OP_COND:
+ case OP_SCOND:
+
+ /* The variable Flength will be added to Fecode when the condition is
+ false, to get to the second branch. Setting it to the offset to the ALT or
+ KET, then incrementing Fecode achieves this effect. However, if the second
+ branch is non-existent, we must point to the KET so that the end of the
+ group is correctly processed. We now have Fecode pointing to the condition
+ or callout. */
+
+ Flength = GET(Fecode, 1); /* Offset to the second branch */
+ if (Fecode[Flength] != OP_ALT) Flength -= 1 + LINK_SIZE;
+ Fecode += 1 + LINK_SIZE; /* From this opcode */
+
+ /* Because of the way auto-callout works during compile, a callout item is
+ inserted between OP_COND and an assertion condition. Such a callout can
+ also be inserted manually. */
+
+ if (*Fecode == OP_CALLOUT || *Fecode == OP_CALLOUT_STR)
+ {
+ rrc = do_callout(F, mb, &length);
+ if (rrc > 0) RRETURN(MATCH_NOMATCH);
+ if (rrc < 0) RRETURN(rrc);
+
+ /* Advance Fecode past the callout, so it now points to the condition. We
+ must adjust Flength so that the value of Fecode+Flength is unchanged. */
+
+ Fecode += length;
+ Flength -= length;
+ }
+
+ /* Test the various possible conditions */
+
+ condition = FALSE;
+ switch(*Fecode)
+ {
+ case OP_RREF: /* Group recursion test */
+ if (Fcurrent_recurse != RECURSE_UNSET)
+ {
+ number = GET2(Fecode, 1);
+ condition = (number == RREF_ANY || number == Fcurrent_recurse);
+ }
+ break;
+
+ case OP_DNRREF: /* Duplicate named group recursion test */
+ if (Fcurrent_recurse != RECURSE_UNSET)
+ {
+ int count = GET2(Fecode, 1 + IMM2_SIZE);
+ PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size;
+ while (count-- > 0)
+ {
+ number = GET2(slot, 0);
+ condition = number == Fcurrent_recurse;
+ if (condition) break;
+ slot += mb->name_entry_size;
+ }
+ }
+ break;
+
+ case OP_CREF: /* Numbered group used test */
+ offset = (GET2(Fecode, 1) << 1) - 2; /* Doubled ref number */
+ condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET;
+ break;
+
+ case OP_DNCREF: /* Duplicate named group used test */
+ {
+ int count = GET2(Fecode, 1 + IMM2_SIZE);
+ PCRE2_SPTR slot = mb->name_table + GET2(Fecode, 1) * mb->name_entry_size;
+ while (count-- > 0)
+ {
+ offset = (GET2(slot, 0) << 1) - 2;
+ condition = offset < Foffset_top && Fovector[offset] != PCRE2_UNSET;
+ if (condition) break;
+ slot += mb->name_entry_size;
+ }
+ }
+ break;
+
+ case OP_FALSE:
+ case OP_FAIL: /* The assertion (?!) becomes OP_FAIL */
+ break;
+
+ case OP_TRUE:
+ condition = TRUE;
+ break;
+
+ /* The condition is an assertion. Run code similar to the assertion code
+ above. */
+
+#define Lpositive F->temp_32[0]
+#define Lstart_branch F->temp_sptr[0]
+
+ default:
+ Lpositive = (*Fecode == OP_ASSERT || *Fecode == OP_ASSERTBACK);
+ Lstart_branch = Fecode;
+
+ for (;;)
+ {
+ group_frame_type = GF_CONDASSERT | *Fecode;
+ RMATCH(Lstart_branch + PRIV(OP_lengths)[*Lstart_branch], RM5);
+
+ switch(rrc)
+ {
+ case MATCH_ACCEPT: /* Save captures */
+ memcpy(Fovector,
+ (char *)assert_accept_frame + offsetof(heapframe, ovector),
+ assert_accept_frame->offset_top * sizeof(PCRE2_SIZE));
+ Foffset_top = assert_accept_frame->offset_top;
+
+ /* Fall through */
+ /* In the case of a match, the captures have already been put into
+ the current frame. */
+
+ case MATCH_MATCH:
+ condition = Lpositive; /* TRUE for positive assertion */
+ break;
+
+ /* PCRE doesn't allow the effect of (*THEN) to escape beyond an
+ assertion; it is therefore always treated as NOMATCH. */
+
+ case MATCH_NOMATCH:
+ case MATCH_THEN:
+ Lstart_branch += GET(Lstart_branch, 1);
+ if (*Lstart_branch == OP_ALT) continue; /* Try next branch */
+ condition = !Lpositive; /* TRUE for negative assertion */
+ break;
+
+ /* These force no match without checking other branches. */
+
+ case MATCH_COMMIT:
+ case MATCH_SKIP:
+ case MATCH_PRUNE:
+ condition = !Lpositive;
+ break;
+
+ default:
+ RRETURN(rrc);
+ }
+ break; /* Out of the branch loop */
+ }
+
+ /* If the condition is true, find the end of the assertion so that
+ advancing past it gets us to the start of the first branch. */
+
+ if (condition)
+ {
+ do Fecode += GET(Fecode, 1); while (*Fecode == OP_ALT);
+ }
+ break; /* End of assertion condition */
+ }
+
+#undef Lpositive
+#undef Lstart_branch
+
+ /* Choose branch according to the condition. */
+
+ Fecode += condition? PRIV(OP_lengths)[*Fecode] : Flength;
+
+ /* If the opcode is OP_SCOND it means we are at a repeated conditional
+ group that might match an empty string. We must therefore descend a level
+ so that the start is remembered for checking. For OP_COND we can just
+ continue at this level. */
+
+ if (Fop == OP_SCOND)
+ {
+ group_frame_type = GF_NOCAPTURE | Fop;
+ RMATCH(Fecode, RM35);
+ RRETURN(rrc);
+ }
+ break;
+
+
+
+/* ========================================================================= */
+/* End of start of parenthesis opcodes */
+/* ========================================================================= */
+
+
+ /* ===================================================================== */
+ /* Move the subject pointer back. This occurs only at the start of each
+ branch of a lookbehind assertion. If we are too close to the start to move
+ back, fail. When working with UTF-8 we move back a number of characters,
+ not bytes. */
+
+ case OP_REVERSE:
+ number = GET(Fecode, 1);
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ while (number-- > 0)
+ {
+ if (Feptr <= mb->start_subject) RRETURN(MATCH_NOMATCH);
+ Feptr--;
+ BACKCHAR(Feptr);
+ }
+ }
+ else
+#endif
+
+ /* No UTF-8 support, or not in UTF-8 mode: count is byte count */
+
+ {
+ if ((ptrdiff_t)number > Feptr - mb->start_subject) RRETURN(MATCH_NOMATCH);
+ Feptr -= number;
+ }
+
+ /* Save the earliest consulted character, then skip to next opcode */
+
+ if (Feptr < mb->start_used_ptr) mb->start_used_ptr = Feptr;
+ Fecode += 1 + LINK_SIZE;
+ break;
+
+
+ /* ===================================================================== */
+ /* An alternation is the end of a branch; scan along to find the end of the
+ bracketed group. */
+
+ case OP_ALT:
+ do Fecode += GET(Fecode,1); while (*Fecode == OP_ALT);
+ break;
+
+
+ /* ===================================================================== */
+ /* The end of a parenthesized group. For all but OP_BRA and OP_COND, the
+ starting frame was added to the chained frames in order to remember the
+ starting subject position for the group. */
+
+ case OP_KET:
+ case OP_KETRMIN:
+ case OP_KETRMAX:
+ case OP_KETRPOS:
+
+ bracode = Fecode - GET(Fecode, 1);
+
+ /* Point N to the frame at the start of the most recent group.
+ Remember the subject pointer at the start of the group. */
+
+ if (*bracode != OP_BRA && *bracode != OP_COND)
+ {
+ N = (heapframe *)((char *)mb->match_frames + Flast_group_offset);
+ P = (heapframe *)((char *)N - frame_size);
+ Flast_group_offset = P->last_group_offset;
+
+#ifdef DEBUG_SHOW_RMATCH
+ fprintf(stderr, "++ KET for frame=%d type=%x prev char offset=%lu\n",
+ N->rdepth, N->group_frame_type,
+ (char *)P->eptr - (char *)mb->start_subject);
+#endif
+
+ /* If we are at the end of an assertion that is a condition, return a
+ match, discarding any intermediate backtracking points. Copy back the
+ captures into the frame before N so that they are set on return. Doing
+ this for all assertions, both positive and negative, seems to match what
+ Perl does. */
+
+ if (GF_IDMASK(N->group_frame_type) == GF_CONDASSERT)
+ {
+ memcpy((char *)P + offsetof(heapframe, ovector), Fovector,
+ Foffset_top * sizeof(PCRE2_SIZE));
+ P->offset_top = Foffset_top;
+ Fback_frame = (char *)F - (char *)P;
+ RRETURN(MATCH_MATCH);
+ }
+ }
+ else P = NULL; /* Indicates starting frame not recorded */
+
+ /* The group was not a conditional assertion. */
+
+ switch (*bracode)
+ {
+ case OP_BRA: /* No need to do anything for these */
+ case OP_COND:
+ case OP_SCOND:
+ break;
+
+ /* Positive assertions are like OP_ONCE, except that in addition the
+ subject pointer must be put back to where it was at the start of the
+ assertion. */
+
+ case OP_ASSERT:
+ case OP_ASSERTBACK:
+ if (Feptr > mb->last_used_ptr) mb->last_used_ptr = Feptr;
+ Feptr = P->eptr;
+ /* Fall through */
+
+ /* For an atomic group, discard internal backtracking points. We must
+ also ensure that any remaining branches within the top-level of the group
+ are not tried. Do this by adjusting the code pointer within the backtrack
+ frame so that it points to the final branch. */
+
+ case OP_ONCE:
+ Fback_frame = ((char *)F - (char *)P);
+ for (;;)
+ {
+ uint32_t y = GET(P->ecode,1);
+ if ((P->ecode)[y] != OP_ALT) break;
+ P->ecode += y;
+ }
+ break;
+
+ /* A matching negative assertion returns MATCH, which is turned into
+ NOMATCH at the assertion level. */
+
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK_NOT:
+ RRETURN(MATCH_MATCH);
+
+ /* Whole-pattern recursion is coded as a recurse into group 0, so it
+ won't be picked up here. Instead, we catch it when the OP_END is reached.
+ Other recursion is handled here. */
+
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRA:
+ case OP_SCBRAPOS:
+ number = GET2(bracode, 1+LINK_SIZE);
+
+ /* Handle a recursively called group. We reinstate the previous set of
+ captures and then carry on after the recursion call. */
+
+ if (Fcurrent_recurse == number)
+ {
+ P = (heapframe *)((char *)N - frame_size);
+ memcpy((char *)F + offsetof(heapframe, ovector), P->ovector,
+ P->offset_top * sizeof(PCRE2_SIZE));
+ Foffset_top = P->offset_top;
+ Fcapture_last = P->capture_last;
+ Fcurrent_recurse = P->current_recurse;
+ Fecode = P->ecode + 1 + LINK_SIZE;
+ continue; /* With next opcode */
+ }
+
+ /* Deal with actual capturing. */
+
+ offset = (number << 1) - 2;
+ Fcapture_last = number;
+ Fovector[offset] = P->eptr - mb->start_subject;
+ Fovector[offset+1] = Feptr - mb->start_subject;
+ if (offset >= Foffset_top) Foffset_top = offset + 2;
+ break;
+ } /* End actions relating to the starting opcode */
+
+ /* OP_KETRPOS is a possessive repeating ket. Remember the current position,
+ and return the MATCH_KETRPOS. This makes it possible to do the repeats one
+ at a time from the outer level. This must precede the empty string test -
+ in this case that test is done at the outer level. */
+
+ if (*Fecode == OP_KETRPOS)
+ {
+ memcpy((char *)P + offsetof(heapframe, eptr),
+ (char *)F + offsetof(heapframe, eptr),
+ frame_copy_size);
+ RRETURN(MATCH_KETRPOS);
+ }
+
+ /* Handle the different kinds of closing brackets. A non-repeating ket
+ needs no special action, just continuing at this level. This also happens
+ for the repeating kets if the group matched no characters, in order to
+ forcibly break infinite loops. Otherwise, the repeating kets try the rest
+ of the pattern or restart from the preceding bracket, in the appropriate
+ order. */
+
+ if (Fop != OP_KET && (P == NULL || Feptr != P->eptr))
+ {
+ if (Fop == OP_KETRMIN)
+ {
+ RMATCH(Fecode + 1 + LINK_SIZE, RM6);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ Fecode -= GET(Fecode, 1);
+ break; /* End of ket processing */
+ }
+
+ /* Repeat the maximum number of times (KETRMAX) */
+
+ RMATCH(bracode, RM7);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ }
+
+ /* Carry on at this level for a non-repeating ket, or after matching an
+ empty string, or after repeating for a maximum number of times. */
+
+ Fecode += 1 + LINK_SIZE;
+ break;
+
+
+ /* ===================================================================== */
+ /* Start and end of line assertions, not multiline mode. */
+
+ case OP_CIRC: /* Start of line, unless PCRE2_NOTBOL is set. */
+ if (Feptr != mb->start_subject || (mb->moptions & PCRE2_NOTBOL) != 0)
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ case OP_SOD: /* Unconditional start of subject */
+ if (Feptr != mb->start_subject) RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ /* When PCRE2_NOTEOL is unset, assert before the subject end, or a
+ terminating newline unless PCRE2_DOLLAR_ENDONLY is set. */
+
+ case OP_DOLL:
+ if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
+ if ((mb->poptions & PCRE2_DOLLAR_ENDONLY) == 0) goto ASSERT_NL_OR_EOS;
+
+ /* Fall through */
+ /* Unconditional end of subject assertion (\z) */
+
+ case OP_EOD:
+ if (Feptr < mb->end_subject) RRETURN(MATCH_NOMATCH);
+ SCHECK_PARTIAL();
+ Fecode++;
+ break;
+
+ /* End of subject or ending \n assertion (\Z) */
+
+ case OP_EODN:
+ ASSERT_NL_OR_EOS:
+ if (Feptr < mb->end_subject &&
+ (!IS_NEWLINE(Feptr) || Feptr != mb->end_subject - mb->nllen))
+ {
+ if (mb->partial != 0 &&
+ Feptr + 1 >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ UCHAR21TEST(Feptr) == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+
+ /* Either at end of string or \n before end. */
+
+ SCHECK_PARTIAL();
+ Fecode++;
+ break;
+
+
+ /* ===================================================================== */
+ /* Start and end of line assertions, multiline mode. */
+
+ /* Start of subject unless notbol, or after any newline except for one at
+ the very end, unless PCRE2_ALT_CIRCUMFLEX is set. */
+
+ case OP_CIRCM:
+ if ((mb->moptions & PCRE2_NOTBOL) != 0 && Feptr == mb->start_subject)
+ RRETURN(MATCH_NOMATCH);
+ if (Feptr != mb->start_subject &&
+ ((Feptr == mb->end_subject &&
+ (mb->poptions & PCRE2_ALT_CIRCUMFLEX) == 0) ||
+ !WAS_NEWLINE(Feptr)))
+ RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+ /* Assert before any newline, or before end of subject unless noteol is
+ set. */
+
+ case OP_DOLLM:
+ if (Feptr < mb->end_subject)
+ {
+ if (!IS_NEWLINE(Feptr))
+ {
+ if (mb->partial != 0 &&
+ Feptr + 1 >= mb->end_subject &&
+ NLBLOCK->nltype == NLTYPE_FIXED &&
+ NLBLOCK->nllen == 2 &&
+ UCHAR21TEST(Feptr) == NLBLOCK->nl[0])
+ {
+ mb->hitend = TRUE;
+ if (mb->partial > 1) return PCRE2_ERROR_PARTIAL;
+ }
+ RRETURN(MATCH_NOMATCH);
+ }
+ }
+ else
+ {
+ if ((mb->moptions & PCRE2_NOTEOL) != 0) RRETURN(MATCH_NOMATCH);
+ SCHECK_PARTIAL();
+ }
+ Fecode++;
+ break;
+
+
+ /* ===================================================================== */
+ /* Start of match assertion */
+
+ case OP_SOM:
+ if (Feptr != mb->start_subject + mb->start_offset) RRETURN(MATCH_NOMATCH);
+ Fecode++;
+ break;
+
+
+ /* ===================================================================== */
+ /* Reset the start of match point */
+
+ case OP_SET_SOM:
+ Fstart_match = Feptr;
+ Fecode++;
+ break;
+
+
+ /* ===================================================================== */
+ /* Word boundary assertions. Find out if the previous and current
+ characters are "word" characters. It takes a bit more work in UTF mode.
+ Characters > 255 are assumed to be "non-word" characters when PCRE2_UCP is
+ not set. When it is set, use Unicode properties if available, even when not
+ in UTF mode. Remember the earliest and latest consulted characters. */
+
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ if (Feptr == mb->start_subject) prev_is_word = FALSE; else
+ {
+ PCRE2_SPTR lastptr = Feptr - 1;
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ BACKCHAR(lastptr);
+ GETCHAR(fc, lastptr);
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ fc = *lastptr;
+ if (lastptr < mb->start_used_ptr) mb->start_used_ptr = lastptr;
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
+ {
+ if (fc == '_') prev_is_word = TRUE; else
+ {
+ int cat = UCD_CATEGORY(fc);
+ prev_is_word = (cat == ucp_L || cat == ucp_N);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ prev_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0;
+ }
+
+ /* Get status of next character */
+
+ if (Feptr >= mb->end_subject)
+ {
+ SCHECK_PARTIAL();
+ cur_is_word = FALSE;
+ }
+ else
+ {
+ PCRE2_SPTR nextptr = Feptr + 1;
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ FORWARDCHARTEST(nextptr, mb->end_subject);
+ GETCHAR(fc, Feptr);
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ fc = *Feptr;
+ if (nextptr > mb->last_used_ptr) mb->last_used_ptr = nextptr;
+#ifdef SUPPORT_UNICODE
+ if ((mb->poptions & PCRE2_UCP) != 0)
+ {
+ if (fc == '_') cur_is_word = TRUE; else
+ {
+ int cat = UCD_CATEGORY(fc);
+ cur_is_word = (cat == ucp_L || cat == ucp_N);
+ }
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+ cur_is_word = CHMAX_255(fc) && (mb->ctypes[fc] & ctype_word) != 0;
+ }
+
+ /* Now see if the situation is what we want */
+
+ if ((*Fecode++ == OP_WORD_BOUNDARY)?
+ cur_is_word == prev_is_word : cur_is_word != prev_is_word)
+ RRETURN(MATCH_NOMATCH);
+ break;
+
+
+ /* ===================================================================== */
+ /* Backtracking (*VERB)s, with and without arguments. Note that if the
+ pattern is successfully matched, we do not come back from RMATCH. */
+
+ case OP_MARK:
+ Fmark = mb->nomatch_mark = Fecode + 2;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM12);
+
+ /* A return of MATCH_SKIP_ARG means that matching failed at SKIP with an
+ argument, and we must check whether that argument matches this MARK's
+ argument. It is passed back in mb->verb_skip_ptr. If it does match, we
+ return MATCH_SKIP with mb->verb_skip_ptr now pointing to the subject
+ position that corresponds to this mark. Otherwise, pass back the return
+ code unaltered. */
+
+ if (rrc == MATCH_SKIP_ARG &&
+ PRIV(strcmp)(Fecode + 2, mb->verb_skip_ptr) == 0)
+ {
+ mb->verb_skip_ptr = Feptr; /* Pass back current position */
+ RRETURN(MATCH_SKIP);
+ }
+ RRETURN(rrc);
+
+ case OP_FAIL:
+ RRETURN(MATCH_NOMATCH);
+
+ /* Record the current recursing group number in mb->verb_current_recurse
+ when a backtracking return such as MATCH_COMMIT is given. This enables the
+ recurse processing to catch verbs from within the recursion. */
+
+ case OP_COMMIT:
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM13);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_COMMIT);
+
+ case OP_COMMIT_ARG:
+ Fmark = mb->nomatch_mark = Fecode + 2;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM36);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_COMMIT);
+
+ case OP_PRUNE:
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM14);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_PRUNE);
+
+ case OP_PRUNE_ARG:
+ Fmark = mb->nomatch_mark = Fecode + 2;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM15);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_PRUNE);
+
+ case OP_SKIP:
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM16);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_skip_ptr = Feptr; /* Pass back current position */
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_SKIP);
+
+ /* Note that, for Perl compatibility, SKIP with an argument does NOT set
+ nomatch_mark. When a pattern match ends with a SKIP_ARG for which there was
+ not a matching mark, we have to re-run the match, ignoring the SKIP_ARG
+ that failed and any that precede it (either they also failed, or were not
+ triggered). To do this, we maintain a count of executed SKIP_ARGs. If a
+ SKIP_ARG gets to top level, the match is re-run with mb->ignore_skip_arg
+ set to the count of the one that failed. */
+
+ case OP_SKIP_ARG:
+ mb->skip_arg_count++;
+ if (mb->skip_arg_count <= mb->ignore_skip_arg)
+ {
+ Fecode += PRIV(OP_lengths)[*Fecode] + Fecode[1];
+ break;
+ }
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM17);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+
+ /* Pass back the current skip name and return the special MATCH_SKIP_ARG
+ return code. This will either be caught by a matching MARK, or get to the
+ top, where it causes a rematch with mb->ignore_skip_arg set to the value of
+ mb->skip_arg_count. */
+
+ mb->verb_skip_ptr = Fecode + 2;
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_SKIP_ARG);
+
+ /* For THEN (and THEN_ARG) we pass back the address of the opcode, so that
+ the branch in which it occurs can be determined. */
+
+ case OP_THEN:
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode], RM18);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_ecode_ptr = Fecode;
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_THEN);
+
+ case OP_THEN_ARG:
+ Fmark = mb->nomatch_mark = Fecode + 2;
+ RMATCH(Fecode + PRIV(OP_lengths)[*Fecode] + Fecode[1], RM19);
+ if (rrc != MATCH_NOMATCH) RRETURN(rrc);
+ mb->verb_ecode_ptr = Fecode;
+ mb->verb_current_recurse = Fcurrent_recurse;
+ RRETURN(MATCH_THEN);
+
+
+ /* ===================================================================== */
+ /* There's been some horrible disaster. Arrival here can only mean there is
+ something seriously wrong in the code above or the OP_xxx definitions. */
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+
+ /* Do not insert any code in here without much thought; it is assumed
+ that "continue" in the code above comes out to here to repeat the main
+ loop. */
+
+ } /* End of main loop */
+/* Control never reaches here */
+
+
+/* ========================================================================= */
+/* The RRETURN() macro jumps here. The number that is saved in Freturn_id
+indicates which label we actually want to return to. The value in Frdepth is
+the index number of the frame in the vector. The return value has been placed
+in rrc. */
+
+#define LBL(val) case val: goto L_RM##val;
+
+RETURN_SWITCH:
+if (Frdepth == 0) return rrc; /* Exit from the top level */
+F = (heapframe *)((char *)F - Fback_frame); /* Backtrack */
+mb->cb->callout_flags |= PCRE2_CALLOUT_BACKTRACK; /* Note for callouts */
+
+#ifdef DEBUG_SHOW_RMATCH
+fprintf(stderr, "++ RETURN %d to %d\n", rrc, Freturn_id);
+#endif
+
+switch (Freturn_id)
+ {
+ LBL( 1) LBL( 2) LBL( 3) LBL( 4) LBL( 5) LBL( 6) LBL( 7) LBL( 8)
+ LBL( 9) LBL(10) LBL(11) LBL(12) LBL(13) LBL(14) LBL(15) LBL(16)
+ LBL(17) LBL(18) LBL(19) LBL(20) LBL(21) LBL(22) LBL(23) LBL(24)
+ LBL(25) LBL(26) LBL(27) LBL(28) LBL(29) LBL(30) LBL(31) LBL(32)
+ LBL(33) LBL(34) LBL(35) LBL(36)
+
+#ifdef SUPPORT_WIDE_CHARS
+ LBL(100) LBL(101)
+#endif
+
+#ifdef SUPPORT_UNICODE
+ LBL(200) LBL(201) LBL(202) LBL(203) LBL(204) LBL(205) LBL(206)
+ LBL(207) LBL(208) LBL(209) LBL(210) LBL(211) LBL(212) LBL(213)
+ LBL(214) LBL(215) LBL(216) LBL(217) LBL(218) LBL(219) LBL(220)
+ LBL(221) LBL(222)
+#endif
+
+ default:
+ return PCRE2_ERROR_INTERNAL;
+ }
+#undef LBL
+}
+
+
+/*************************************************
+* Match a Regular Expression *
+*************************************************/
+
+/* This function applies a compiled pattern to a subject string and picks out
+portions of the string if it matches. Two elements in the vector are set for
+each substring: the offsets to the start and end of the substring.
+
+Arguments:
+ code points to the compiled expression
+ subject points to the subject string
+ length length of subject string (may contain binary zeros)
+ start_offset where to start in the subject string
+ options option bits
+ match_data points to a match_data block
+ mcontext points a PCRE2 context
+
+Returns: > 0 => success; value is the number of ovector pairs filled
+ = 0 => success, but ovector is not big enough
+ -1 => failed to match (PCRE2_ERROR_NOMATCH)
+ -2 => partial match (PCRE2_ERROR_PARTIAL)
+ < -2 => some kind of unexpected problem
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_match(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext)
+{
+int rc;
+const uint8_t *start_bits = NULL;
+
+const pcre2_real_code *re = (const pcre2_real_code *)code;
+
+BOOL anchored;
+BOOL firstline;
+BOOL has_first_cu = FALSE;
+BOOL has_req_cu = FALSE;
+BOOL startline;
+BOOL utf;
+
+PCRE2_UCHAR first_cu = 0;
+PCRE2_UCHAR first_cu2 = 0;
+PCRE2_UCHAR req_cu = 0;
+PCRE2_UCHAR req_cu2 = 0;
+
+PCRE2_SPTR bumpalong_limit;
+PCRE2_SPTR end_subject;
+PCRE2_SPTR start_match = subject + start_offset;
+PCRE2_SPTR req_cu_ptr = start_match - 1;
+PCRE2_SPTR start_partial = NULL;
+PCRE2_SPTR match_partial = NULL;
+
+PCRE2_SIZE frame_size;
+
+/* We need to have mb as a pointer to a match block, because the IS_NEWLINE
+macro is used below, and it expects NLBLOCK to be defined as a pointer. */
+
+pcre2_callout_block cb;
+match_block actual_match_block;
+match_block *mb = &actual_match_block;
+
+/* Allocate an initial vector of backtracking frames on the stack. If this
+proves to be too small, it is replaced by a larger one on the heap. To get a
+vector of the size required that is aligned for pointers, allocate it as a
+vector of pointers. */
+
+PCRE2_SPTR stack_frames_vector[START_FRAMES_SIZE/sizeof(PCRE2_SPTR)];
+mb->stack_frames = (heapframe *)stack_frames_vector;
+
+/* A length equal to PCRE2_ZERO_TERMINATED implies a zero-terminated
+subject string. */
+
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
+end_subject = subject + length;
+
+/* Plausibility checks */
+
+if ((options & ~PUBLIC_MATCH_OPTIONS) != 0) return PCRE2_ERROR_BADOPTION;
+if (code == NULL || subject == NULL || match_data == NULL)
+ return PCRE2_ERROR_NULL;
+if (start_offset > length) return PCRE2_ERROR_BADOFFSET;
+
+/* Check that the first field in the block is the magic number. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check the code unit width. */
+
+if ((re->flags & PCRE2_MODE_MASK) != PCRE2_CODE_UNIT_WIDTH/8)
+ return PCRE2_ERROR_BADMODE;
+
+/* PCRE2_NOTEMPTY and PCRE2_NOTEMPTY_ATSTART are match-time flags in the
+options variable for this function. Users of PCRE2 who are not calling the
+function directly would like to have a way of setting these flags, in the same
+way that they can set pcre2_compile() flags like PCRE2_NO_AUTOPOSSESS with
+constructions like (*NO_AUTOPOSSESS). To enable this, (*NOTEMPTY) and
+(*NOTEMPTY_ATSTART) set bits in the pattern's "flag" function which we now
+transfer to the options for this function. The bits are guaranteed to be
+adjacent, but do not have the same values. This bit of Boolean trickery assumes
+that the match-time bits are not more significant than the flag bits. If by
+accident this is not the case, a compile-time division by zero error will
+occur. */
+
+#define FF (PCRE2_NOTEMPTY_SET|PCRE2_NE_ATST_SET)
+#define OO (PCRE2_NOTEMPTY|PCRE2_NOTEMPTY_ATSTART)
+options |= (re->flags & FF) / ((FF & (~FF+1)) / (OO & (~OO+1)));
+#undef FF
+#undef OO
+
+/* These two settings are used in the code for checking a UTF string that
+follows immediately afterwards. Other values in the mb block are used only
+during interpretive processing, not when the JIT support is in use, so they are
+set up later. */
+
+utf = (re->overall_options & PCRE2_UTF) != 0;
+mb->partial = ((options & PCRE2_PARTIAL_HARD) != 0)? 2 :
+ ((options & PCRE2_PARTIAL_SOFT) != 0)? 1 : 0;
+
+/* Partial matching and PCRE2_ENDANCHORED are currently not allowed at the same
+time. */
+
+if (mb->partial != 0 &&
+ ((re->overall_options | options) & PCRE2_ENDANCHORED) != 0)
+ return PCRE2_ERROR_BADOPTION;
+
+/* Check a UTF string for validity if required. For 8-bit and 16-bit strings,
+we must also check that a starting offset does not point into the middle of a
+multiunit character. We check only the portion of the subject that is going to
+be inspected during matching - from the offset minus the maximum back reference
+to the given length. This saves time when a small part of a large subject is
+being matched by the use of a starting offset. Note that the maximum lookbehind
+is a number of characters, not code units. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
+ {
+ PCRE2_SPTR check_subject = start_match; /* start_match includes offset */
+
+ if (start_offset > 0)
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 32
+ unsigned int i;
+ if (start_match < end_subject && NOT_FIRSTCU(*start_match))
+ return PCRE2_ERROR_BADUTFOFFSET;
+ for (i = re->max_lookbehind; i > 0 && check_subject > subject; i--)
+ {
+ check_subject--;
+ while (check_subject > subject &&
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ (*check_subject & 0xc0) == 0x80)
+#else /* 16-bit */
+ (*check_subject & 0xfc00) == 0xdc00)
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+ check_subject--;
+ }
+#else
+ /* In the 32-bit library, one code unit equals one character. However,
+ we cannot just subtract the lookbehind and then compare pointers, because
+ a very large lookbehind could create an invalid pointer. */
+
+ if (start_offset >= re->max_lookbehind)
+ check_subject -= re->max_lookbehind;
+ else
+ check_subject = subject;
+#endif /* PCRE2_CODE_UNIT_WIDTH != 32 */
+ }
+
+ /* Validate the relevant portion of the subject. After an error, adjust the
+ offset to be an absolute offset in the whole string. */
+
+ match_data->rc = PRIV(valid_utf)(check_subject,
+ length - (check_subject - subject), &(match_data->startchar));
+ if (match_data->rc != 0)
+ {
+ match_data->startchar += check_subject - subject;
+ return match_data->rc;
+ }
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* It is an error to set an offset limit without setting the flag at compile
+time. */
+
+if (mcontext != NULL && mcontext->offset_limit != PCRE2_UNSET &&
+ (re->overall_options & PCRE2_USE_OFFSET_LIMIT) == 0)
+ return PCRE2_ERROR_BADOFFSETLIMIT;
+
+/* If the pattern was successfully studied with JIT support, run the JIT
+executable instead of the rest of this function. Most options must be set at
+compile time for the JIT code to be usable. Fallback to the normal code path if
+an unsupported option is set or if JIT returns BADOPTION (which means that the
+selected normal or partial matching mode was not compiled). */
+
+#ifdef SUPPORT_JIT
+if (re->executable_jit != NULL && (options & ~PUBLIC_JIT_MATCH_OPTIONS) == 0)
+ {
+ rc = pcre2_jit_match(code, subject, length, start_offset, options,
+ match_data, mcontext);
+ if (rc != PCRE2_ERROR_JIT_BADOPTION) return rc;
+ }
+#endif
+
+/* Carry on with non-JIT matching. A NULL match context means "use a default
+context", but we take the memory control functions from the pattern. */
+
+if (mcontext == NULL)
+ {
+ mcontext = (pcre2_match_context *)(&PRIV(default_match_context));
+ mb->memctl = re->memctl;
+ }
+else mb->memctl = mcontext->memctl;
+
+anchored = ((re->overall_options | options) & PCRE2_ANCHORED) != 0;
+firstline = (re->overall_options & PCRE2_FIRSTLINE) != 0;
+startline = (re->flags & PCRE2_STARTLINE) != 0;
+bumpalong_limit = (mcontext->offset_limit == PCRE2_UNSET)?
+ end_subject : subject + mcontext->offset_limit;
+
+/* Initialize and set up the fixed fields in the callout block, with a pointer
+in the match block. */
+
+mb->cb = &cb;
+cb.version = 2;
+cb.subject = subject;
+cb.subject_length = (PCRE2_SIZE)(end_subject - subject);
+cb.callout_flags = 0;
+
+/* Fill in the remaining fields in the match block. */
+
+mb->callout = mcontext->callout;
+mb->callout_data = mcontext->callout_data;
+
+mb->start_subject = subject;
+mb->start_offset = start_offset;
+mb->end_subject = end_subject;
+mb->hasthen = (re->flags & PCRE2_HASTHEN) != 0;
+
+mb->moptions = options; /* Match options */
+mb->poptions = re->overall_options; /* Pattern options */
+
+mb->ignore_skip_arg = 0;
+mb->mark = mb->nomatch_mark = NULL; /* In case never set */
+mb->hitend = FALSE;
+
+/* The name table is needed for finding all the numbers associated with a
+given name, for condition testing. The code follows the name table. */
+
+mb->name_table = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code));
+mb->name_count = re->name_count;
+mb->name_entry_size = re->name_entry_size;
+mb->start_code = mb->name_table + re->name_count * re->name_entry_size;
+
+/* Process the \R and newline settings. */
+
+mb->bsr_convention = re->bsr_convention;
+mb->nltype = NLTYPE_FIXED;
+switch(re->newline_convention)
+ {
+ case PCRE2_NEWLINE_CR:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_CR;
+ break;
+
+ case PCRE2_NEWLINE_LF:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_NUL:
+ mb->nllen = 1;
+ mb->nl[0] = CHAR_NUL;
+ break;
+
+ case PCRE2_NEWLINE_CRLF:
+ mb->nllen = 2;
+ mb->nl[0] = CHAR_CR;
+ mb->nl[1] = CHAR_NL;
+ break;
+
+ case PCRE2_NEWLINE_ANY:
+ mb->nltype = NLTYPE_ANY;
+ break;
+
+ case PCRE2_NEWLINE_ANYCRLF:
+ mb->nltype = NLTYPE_ANYCRLF;
+ break;
+
+ default: return PCRE2_ERROR_INTERNAL;
+ }
+
+/* The backtracking frames have fixed data at the front, and a PCRE2_SIZE
+vector at the end, whose size depends on the number of capturing parentheses in
+the pattern. It is not used at all if there are no capturing parentheses.
+
+ frame_size is the total size of each frame
+ mb->frame_vector_size is the total usable size of the vector (rounded down
+ to a whole number of frames)
+
+The last of these is changed within the match() function if the frame vector
+has to be expanded. We therefore put it into the match block so that it is
+correct when calling match() more than once for non-anchored patterns. */
+
+frame_size = offsetof(heapframe, ovector) +
+ re->top_bracket * 2 * sizeof(PCRE2_SIZE);
+
+/* Limits set in the pattern override the match context only if they are
+smaller. */
+
+mb->heap_limit = (mcontext->heap_limit < re->limit_heap)?
+ mcontext->heap_limit : re->limit_heap;
+
+mb->match_limit = (mcontext->match_limit < re->limit_match)?
+ mcontext->match_limit : re->limit_match;
+
+mb->match_limit_depth = (mcontext->depth_limit < re->limit_depth)?
+ mcontext->depth_limit : re->limit_depth;
+
+/* If a pattern has very many capturing parentheses, the frame size may be very
+large. Ensure that there are at least 10 available frames by getting an initial
+vector on the heap if necessary, except when the heap limit prevents this. Get
+fewer if possible. (The heap limit is in kibibytes.) */
+
+if (frame_size <= START_FRAMES_SIZE/10)
+ {
+ mb->match_frames = mb->stack_frames; /* Initial frame vector on the stack */
+ mb->frame_vector_size = ((START_FRAMES_SIZE/frame_size) * frame_size);
+ }
+else
+ {
+ mb->frame_vector_size = frame_size * 10;
+ if ((mb->frame_vector_size / 1024) > mb->heap_limit)
+ {
+ if (frame_size > mb->heap_limit * 1024) return PCRE2_ERROR_HEAPLIMIT;
+ mb->frame_vector_size = ((mb->heap_limit * 1024)/frame_size) * frame_size;
+ }
+ mb->match_frames = mb->memctl.malloc(mb->frame_vector_size,
+ mb->memctl.memory_data);
+ if (mb->match_frames == NULL) return PCRE2_ERROR_NOMEMORY;
+ }
+
+mb->match_frames_top =
+ (heapframe *)((char *)mb->match_frames + mb->frame_vector_size);
+
+/* Write to the ovector within the first frame to mark every capture unset and
+to avoid uninitialized memory read errors when it is copied to a new frame. */
+
+memset((char *)(mb->match_frames) + offsetof(heapframe, ovector), 0xff,
+ re->top_bracket * 2 * sizeof(PCRE2_SIZE));
+
+/* Pointers to the individual character tables */
+
+mb->lcc = re->tables + lcc_offset;
+mb->fcc = re->tables + fcc_offset;
+mb->ctypes = re->tables + ctypes_offset;
+
+/* Set up the first code unit to match, if available. If there's no first code
+unit there may be a bitmap of possible first characters. */
+
+if ((re->flags & PCRE2_FIRSTSET) != 0)
+ {
+ has_first_cu = TRUE;
+ first_cu = first_cu2 = (PCRE2_UCHAR)(re->first_codeunit);
+ if ((re->flags & PCRE2_FIRSTCASELESS) != 0)
+ {
+ first_cu2 = TABLE_GET(first_cu, mb->fcc, first_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && first_cu > 127) first_cu2 = UCD_OTHERCASE(first_cu);
+#endif
+ }
+ }
+else
+ if (!startline && (re->flags & PCRE2_FIRSTMAPSET) != 0)
+ start_bits = re->start_bitmap;
+
+/* There may also be a "last known required character" set. */
+
+if ((re->flags & PCRE2_LASTSET) != 0)
+ {
+ has_req_cu = TRUE;
+ req_cu = req_cu2 = (PCRE2_UCHAR)(re->last_codeunit);
+ if ((re->flags & PCRE2_LASTCASELESS) != 0)
+ {
+ req_cu2 = TABLE_GET(req_cu, mb->fcc, req_cu);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH != 8
+ if (utf && req_cu > 127) req_cu2 = UCD_OTHERCASE(req_cu);
+#endif
+ }
+ }
+
+
+/* ==========================================================================*/
+
+/* Loop for handling unanchored repeated matching attempts; for anchored regexs
+the loop runs just once. */
+
+for(;;)
+ {
+ PCRE2_SPTR new_start_match;
+
+ /* ----------------- Start of match optimizations ---------------- */
+
+ /* There are some optimizations that avoid running the match if a known
+ starting point is not found, or if a known later code unit is not present.
+ However, there is an option (settable at compile time) that disables these,
+ for testing and for ensuring that all callouts do actually occur. */
+
+ if ((re->overall_options & PCRE2_NO_START_OPTIMIZE) == 0)
+ {
+ /* If firstline is TRUE, the start of the match is constrained to the first
+ line of a multiline string. That is, the match must be before or at the
+ first newline following the start of matching. Temporarily adjust
+ end_subject so that we stop the scans for a first code unit at a newline.
+ If the match fails at the newline, later code breaks the loop. */
+
+ if (firstline)
+ {
+ PCRE2_SPTR t = start_match;
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ while (t < end_subject && !IS_NEWLINE(t))
+ {
+ t++;
+ ACROSSCHAR(t < end_subject, t, t++);
+ }
+ }
+ else
+#endif
+ while (t < end_subject && !IS_NEWLINE(t)) t++;
+ end_subject = t;
+ }
+
+ /* Anchored: check the first code unit if one is recorded. This may seem
+ pointless but it can help in detecting a no match case without scanning for
+ the required code unit. */
+
+ if (anchored)
+ {
+ if (has_first_cu || start_bits != NULL)
+ {
+ BOOL ok = start_match < end_subject;
+ if (ok)
+ {
+ PCRE2_UCHAR c = UCHAR21TEST(start_match);
+ ok = has_first_cu && (c == first_cu || c == first_cu2);
+ if (!ok && start_bits != NULL)
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (c > 255) c = 255;
+#endif
+ ok = (start_bits[c/8] & (1 << (c&7))) != 0;
+ }
+ }
+ if (!ok)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
+ }
+ }
+
+ /* Not anchored. Advance to a unique first code unit if there is one. In
+ 8-bit mode, the use of memchr() gives a big speed up, even though we have
+ to call it twice in caseless mode, in order to find the earliest occurrence
+ of the character in either of its cases. */
+
+ else
+ {
+ if (has_first_cu)
+ {
+ if (first_cu != first_cu2) /* Caseless */
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ PCRE2_UCHAR smc;
+ while (start_match < end_subject &&
+ (smc = UCHAR21TEST(start_match)) != first_cu &&
+ smc != first_cu2)
+ start_match++;
+#else /* 8-bit code units */
+ PCRE2_SPTR pp1 =
+ memchr(start_match, first_cu, end_subject-start_match);
+ PCRE2_SPTR pp2 =
+ memchr(start_match, first_cu2, end_subject-start_match);
+ if (pp1 == NULL)
+ start_match = (pp2 == NULL)? end_subject : pp2;
+ else
+ start_match = (pp2 == NULL || pp1 < pp2)? pp1 : pp2;
+#endif
+ }
+
+ /* The caseful case */
+
+ else
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ while (start_match < end_subject && UCHAR21TEST(start_match) !=
+ first_cu)
+ start_match++;
+#else
+ start_match = memchr(start_match, first_cu, end_subject - start_match);
+ if (start_match == NULL) start_match = end_subject;
+#endif
+ }
+
+ /* If we can't find the required code unit, having reached the true end
+ of the subject, break the bumpalong loop, to force a match failure,
+ except when doing partial matching, when we let the next cycle run at
+ the end of the subject. To see why, consider the pattern /(?<=abc)def/,
+ which partially matches "abc", even though the string does not contain
+ the starting character "d". If we have not reached the true end of the
+ subject (PCRE2_FIRSTLINE caused end_subject to be temporarily modified)
+ we also let the cycle run, because the matching string is legitimately
+ allowed to start with the first code unit of a newline. */
+
+ if (!mb->partial && start_match >= mb->end_subject)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
+ }
+
+ /* If there's no first code unit, advance to just after a linebreak for a
+ multiline match if required. */
+
+ else if (startline)
+ {
+ if (start_match > mb->start_subject + start_offset)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ while (start_match < end_subject && !WAS_NEWLINE(start_match))
+ {
+ start_match++;
+ ACROSSCHAR(start_match < end_subject, start_match, start_match++);
+ }
+ }
+ else
+#endif
+ while (start_match < end_subject && !WAS_NEWLINE(start_match))
+ start_match++;
+
+ /* If we have just passed a CR and the newline option is ANY or
+ ANYCRLF, and we are now at a LF, advance the match position by one
+ more code unit. */
+
+ if (start_match[-1] == CHAR_CR &&
+ (mb->nltype == NLTYPE_ANY || mb->nltype == NLTYPE_ANYCRLF) &&
+ start_match < end_subject &&
+ UCHAR21TEST(start_match) == CHAR_NL)
+ start_match++;
+ }
+ }
+
+ /* If there's no first code unit or a requirement for a multiline line
+ start, advance to a non-unique first code unit if any have been
+ identified. The bitmap contains only 256 bits. When code units are 16 or
+ 32 bits wide, all code units greater than 254 set the 255 bit. */
+
+ else if (start_bits != NULL)
+ {
+ while (start_match < end_subject)
+ {
+ uint32_t c = UCHAR21TEST(start_match);
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ if (c > 255) c = 255;
+#endif
+ if ((start_bits[c/8] & (1 << (c&7))) != 0) break;
+ start_match++;
+ }
+
+ /* See comment above in first_cu checking about the next few lines. */
+
+ if (!mb->partial && start_match >= mb->end_subject)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
+ }
+ } /* End first code unit handling */
+
+ /* Restore fudged end_subject */
+
+ end_subject = mb->end_subject;
+
+ /* The following two optimizations must be disabled for partial matching. */
+
+ if (!mb->partial)
+ {
+ /* The minimum matching length is a lower bound; no string of that length
+ may actually match the pattern. Although the value is, strictly, in
+ characters, we treat it as code units to avoid spending too much time in
+ this optimization. */
+
+ if (end_subject - start_match < re->minlength)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
+
+ /* If req_cu is set, we know that that code unit must appear in the
+ subject for the (non-partial) match to succeed. If the first code unit is
+ set, req_cu must be later in the subject; otherwise the test starts at
+ the match point. This optimization can save a huge amount of backtracking
+ in patterns with nested unlimited repeats that aren't going to match.
+ Writing separate code for caseful/caseless versions makes it go faster,
+ as does using an autoincrement and backing off on a match. As in the case
+ of the first code unit, using memchr() in the 8-bit library gives a big
+ speed up. Unlike the first_cu check above, we do not need to call
+ memchr() twice in the caseless case because we only need to check for the
+ presence of the character in either case, not find the first occurrence.
+
+ HOWEVER: when the subject string is very, very long, searching to its end
+ can take a long time, and give bad performance on quite ordinary
+ patterns. This showed up when somebody was matching something like
+ /^\d+C/ on a 32-megabyte string... so we don't do this when the string is
+ sufficiently long. */
+
+ if (has_req_cu && end_subject - start_match < REQ_CU_MAX)
+ {
+ PCRE2_SPTR p = start_match + (has_first_cu? 1:0);
+
+ /* We don't need to repeat the search if we haven't yet reached the
+ place we found it last time round the bumpalong loop. */
+
+ if (p > req_cu_ptr)
+ {
+ if (p < end_subject)
+ {
+ if (req_cu != req_cu2) /* Caseless */
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ do
+ {
+ uint32_t pp = UCHAR21INCTEST(p);
+ if (pp == req_cu || pp == req_cu2) { p--; break; }
+ }
+ while (p < end_subject);
+
+#else /* 8-bit code units */
+ PCRE2_SPTR pp = p;
+ p = memchr(pp, req_cu, end_subject - pp);
+ if (p == NULL)
+ {
+ p = memchr(pp, req_cu2, end_subject - pp);
+ if (p == NULL) p = end_subject;
+ }
+#endif /* PCRE2_CODE_UNIT_WIDTH != 8 */
+ }
+
+ /* The caseful case */
+
+ else
+ {
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ do
+ {
+ if (UCHAR21INCTEST(p) == req_cu) { p--; break; }
+ }
+ while (p < end_subject);
+
+#else /* 8-bit code units */
+ p = memchr(p, req_cu, end_subject - p);
+ if (p == NULL) p = end_subject;
+#endif
+ }
+ }
+
+ /* If we can't find the required code unit, break the bumpalong loop,
+ forcing a match failure. */
+
+ if (p >= end_subject)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
+
+ /* If we have found the required code unit, save the point where we
+ found it, so that we don't search again next time round the bumpalong
+ loop if the start hasn't yet passed this code unit. */
+
+ req_cu_ptr = p;
+ }
+ }
+ }
+ }
+
+ /* ------------ End of start of match optimizations ------------ */
+
+ /* Give no match if we have passed the bumpalong limit. */
+
+ if (start_match > bumpalong_limit)
+ {
+ rc = MATCH_NOMATCH;
+ break;
+ }
+
+ /* OK, we can now run the match. If "hitend" is set afterwards, remember the
+ first starting point for which a partial match was found. */
+
+ cb.start_match = (PCRE2_SIZE)(start_match - subject);
+ cb.callout_flags |= PCRE2_CALLOUT_STARTMATCH;
+
+ mb->start_used_ptr = start_match;
+ mb->last_used_ptr = start_match;
+ mb->match_call_count = 0;
+ mb->end_offset_top = 0;
+ mb->skip_arg_count = 0;
+
+ rc = match(start_match, mb->start_code, match_data->ovector,
+ match_data->oveccount, re->top_bracket, frame_size, mb);
+
+ if (mb->hitend && start_partial == NULL)
+ {
+ start_partial = mb->start_used_ptr;
+ match_partial = start_match;
+ }
+
+ switch(rc)
+ {
+ /* If MATCH_SKIP_ARG reaches this level it means that a MARK that matched
+ the SKIP's arg was not found. In this circumstance, Perl ignores the SKIP
+ entirely. The only way we can do that is to re-do the match at the same
+ point, with a flag to force SKIP with an argument to be ignored. Just
+ treating this case as NOMATCH does not work because it does not check other
+ alternatives in patterns such as A(*SKIP:A)B|AC when the subject is AC. */
+
+ case MATCH_SKIP_ARG:
+ new_start_match = start_match;
+ mb->ignore_skip_arg = mb->skip_arg_count;
+ break;
+
+ /* SKIP passes back the next starting point explicitly, but if it is no
+ greater than the match we have just done, treat it as NOMATCH. */
+
+ case MATCH_SKIP:
+ if (mb->verb_skip_ptr > start_match)
+ {
+ new_start_match = mb->verb_skip_ptr;
+ break;
+ }
+ /* Fall through */
+
+ /* NOMATCH and PRUNE advance by one character. THEN at this level acts
+ exactly like PRUNE. Unset ignore SKIP-with-argument. */
+
+ case MATCH_NOMATCH:
+ case MATCH_PRUNE:
+ case MATCH_THEN:
+ mb->ignore_skip_arg = 0;
+ new_start_match = start_match + 1;
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ ACROSSCHAR(new_start_match < end_subject, new_start_match,
+ new_start_match++);
+#endif
+ break;
+
+ /* COMMIT disables the bumpalong, but otherwise behaves as NOMATCH. */
+
+ case MATCH_COMMIT:
+ rc = MATCH_NOMATCH;
+ goto ENDLOOP;
+
+ /* Any other return is either a match, or some kind of error. */
+
+ default:
+ goto ENDLOOP;
+ }
+
+ /* Control reaches here for the various types of "no match at this point"
+ result. Reset the code to MATCH_NOMATCH for subsequent checking. */
+
+ rc = MATCH_NOMATCH;
+
+ /* If PCRE2_FIRSTLINE is set, the match must happen before or at the first
+ newline in the subject (though it may continue over the newline). Therefore,
+ if we have just failed to match, starting at a newline, do not continue. */
+
+ if (firstline && IS_NEWLINE(start_match)) break;
+
+ /* Advance to new matching position */
+
+ start_match = new_start_match;
+
+ /* Break the loop if the pattern is anchored or if we have passed the end of
+ the subject. */
+
+ if (anchored || start_match > end_subject) break;
+
+ /* If we have just passed a CR and we are now at a LF, and the pattern does
+ not contain any explicit matches for \r or \n, and the newline option is CRLF
+ or ANY or ANYCRLF, advance the match position by one more code unit. In
+ normal matching start_match will aways be greater than the first position at
+ this stage, but a failed *SKIP can cause a return at the same point, which is
+ why the first test exists. */
+
+ if (start_match > subject + start_offset &&
+ start_match[-1] == CHAR_CR &&
+ start_match < end_subject &&
+ *start_match == CHAR_NL &&
+ (re->flags & PCRE2_HASCRORLF) == 0 &&
+ (mb->nltype == NLTYPE_ANY ||
+ mb->nltype == NLTYPE_ANYCRLF ||
+ mb->nllen == 2))
+ start_match++;
+
+ mb->mark = NULL; /* Reset for start of next match attempt */
+ } /* End of for(;;) "bumpalong" loop */
+
+/* ==========================================================================*/
+
+/* When we reach here, one of the following stopping conditions is true:
+
+(1) The match succeeded, either completely, or partially;
+
+(2) The pattern is anchored or the match was failed after (*COMMIT);
+
+(3) We are past the end of the subject or the bumpalong limit;
+
+(4) PCRE2_FIRSTLINE is set and we have failed to match at a newline, because
+ this option requests that a match occur at or before the first newline in
+ the subject.
+
+(5) Some kind of error occurred.
+
+*/
+
+ENDLOOP:
+
+/* Release an enlarged frame vector that is on the heap. */
+
+if (mb->match_frames != mb->stack_frames)
+ mb->memctl.free(mb->match_frames, mb->memctl.memory_data);
+
+/* Fill in fields that are always returned in the match data. */
+
+match_data->code = re;
+match_data->subject = subject;
+match_data->mark = mb->mark;
+match_data->matchedby = PCRE2_MATCHEDBY_INTERPRETER;
+
+/* Handle a fully successful match. Set the return code to the number of
+captured strings, or 0 if there were too many to fit into the ovector, and then
+set the remaining returned values before returning. */
+
+if (rc == MATCH_MATCH)
+ {
+ match_data->rc = ((int)mb->end_offset_top >= 2 * match_data->oveccount)?
+ 0 : (int)mb->end_offset_top/2 + 1;
+ match_data->startchar = start_match - subject;
+ match_data->leftchar = mb->start_used_ptr - subject;
+ match_data->rightchar = ((mb->last_used_ptr > mb->end_match_ptr)?
+ mb->last_used_ptr : mb->end_match_ptr) - subject;
+ return match_data->rc;
+ }
+
+/* Control gets here if there has been a partial match, an error, or if the
+overall match attempt has failed at all permitted starting positions. Any mark
+data is in the nomatch_mark field. */
+
+match_data->mark = mb->nomatch_mark;
+
+/* For anything other than nomatch or partial match, just return the code. */
+
+if (rc != MATCH_NOMATCH && rc != PCRE2_ERROR_PARTIAL) match_data->rc = rc;
+
+/* Handle a partial match. */
+
+else if (match_partial != NULL)
+ {
+ match_data->ovector[0] = match_partial - subject;
+ match_data->ovector[1] = end_subject - subject;
+ match_data->startchar = match_partial - subject;
+ match_data->leftchar = start_partial - subject;
+ match_data->rightchar = end_subject - subject;
+ match_data->rc = PCRE2_ERROR_PARTIAL;
+ }
+
+/* Else this is the classic nomatch case. */
+
+else match_data->rc = PCRE2_ERROR_NOMATCH;
+
+return match_data->rc;
+}
+
+/* End of pcre2_match.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_match_data.c b/test/monniaux/pcre2-10.32/pcre2_match_data.c
new file mode 100644
index 00000000..b297f326
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_match_data.c
@@ -0,0 +1,147 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2017 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Create a match data block given ovector size *
+*************************************************/
+
+/* A minimum of 1 is imposed on the number of ovector pairs. */
+
+PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
+pcre2_match_data_create(uint32_t oveccount, pcre2_general_context *gcontext)
+{
+pcre2_match_data *yield;
+if (oveccount < 1) oveccount = 1;
+yield = PRIV(memctl_malloc)(
+ offsetof(pcre2_match_data, ovector) + 2*oveccount*sizeof(PCRE2_SIZE),
+ (pcre2_memctl *)gcontext);
+if (yield == NULL) return NULL;
+yield->oveccount = oveccount;
+return yield;
+}
+
+
+
+/*************************************************
+* Create a match data block using pattern data *
+*************************************************/
+
+/* If no context is supplied, use the memory allocator from the code. */
+
+PCRE2_EXP_DEFN pcre2_match_data * PCRE2_CALL_CONVENTION
+pcre2_match_data_create_from_pattern(const pcre2_code *code,
+ pcre2_general_context *gcontext)
+{
+if (gcontext == NULL) gcontext = (pcre2_general_context *)code;
+return pcre2_match_data_create(((pcre2_real_code *)code)->top_bracket + 1,
+ gcontext);
+}
+
+
+
+/*************************************************
+* Free a match data block *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_match_data_free(pcre2_match_data *match_data)
+{
+if (match_data != NULL)
+ match_data->memctl.free(match_data, match_data->memctl.memory_data);
+}
+
+
+
+/*************************************************
+* Get last mark in match *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SPTR PCRE2_CALL_CONVENTION
+pcre2_get_mark(pcre2_match_data *match_data)
+{
+return match_data->mark;
+}
+
+
+
+/*************************************************
+* Get pointer to ovector *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE * PCRE2_CALL_CONVENTION
+pcre2_get_ovector_pointer(pcre2_match_data *match_data)
+{
+return match_data->ovector;
+}
+
+
+
+/*************************************************
+* Get number of ovector slots *
+*************************************************/
+
+PCRE2_EXP_DEFN uint32_t PCRE2_CALL_CONVENTION
+pcre2_get_ovector_count(pcre2_match_data *match_data)
+{
+return match_data->oveccount;
+}
+
+
+
+/*************************************************
+* Get starting code unit in match *
+*************************************************/
+
+PCRE2_EXP_DEFN PCRE2_SIZE PCRE2_CALL_CONVENTION
+pcre2_get_startchar(pcre2_match_data *match_data)
+{
+return match_data->startchar;
+}
+
+/* End of pcre2_match_data.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_newline.c b/test/monniaux/pcre2-10.32/pcre2_newline.c
new file mode 100644
index 00000000..6e9366db
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_newline.c
@@ -0,0 +1,243 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains internal functions for testing newlines when more than
+one kind of newline is to be recognized. When a newline is found, its length is
+returned. In principle, we could implement several newline "types", each
+referring to a different set of newline characters. At present, PCRE2 supports
+only NLTYPE_FIXED, which gets handled without these functions, NLTYPE_ANYCRLF,
+and NLTYPE_ANY. The full list of Unicode newline characters is taken from
+http://unicode.org/unicode/reports/tr18/. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Check for newline at given position *
+*************************************************/
+
+/* This function is called only via the IS_NEWLINE macro, which does so only
+when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed
+newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the code unit
+pointed to by ptr is less than the end of the string.
+
+Arguments:
+ ptr pointer to possible newline
+ type the newline type
+ endptr pointer to the end of the string
+ lenptr where to return the length
+ utf TRUE if in utf mode
+
+Returns: TRUE or FALSE
+*/
+
+BOOL
+PRIV(is_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR endptr,
+ uint32_t *lenptr, BOOL utf)
+{
+uint32_t c;
+
+#ifdef SUPPORT_UNICODE
+if (utf) { GETCHAR(c, ptr); } else c = *ptr;
+#else
+(void)utf;
+c = *ptr;
+#endif /* SUPPORT_UNICODE */
+
+if (type == NLTYPE_ANYCRLF) switch(c)
+ {
+ case CHAR_LF:
+ *lenptr = 1;
+ return TRUE;
+
+ case CHAR_CR:
+ *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
+/* NLTYPE_ANY */
+
+else switch(c)
+ {
+#ifdef EBCDIC
+ case CHAR_NEL:
+#endif
+ case CHAR_LF:
+ case CHAR_VT:
+ case CHAR_FF:
+ *lenptr = 1;
+ return TRUE;
+
+ case CHAR_CR:
+ *lenptr = (ptr < endptr - 1 && ptr[1] == CHAR_LF)? 2 : 1;
+ return TRUE;
+
+#ifndef EBCDIC
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ case CHAR_NEL:
+ *lenptr = utf? 2 : 1;
+ return TRUE;
+
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 3;
+ return TRUE;
+
+#else /* 16-bit or 32-bit code units */
+ case CHAR_NEL:
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 1;
+ return TRUE;
+#endif
+#endif /* Not EBCDIC */
+
+ default:
+ return FALSE;
+ }
+}
+
+
+
+/*************************************************
+* Check for newline at previous position *
+*************************************************/
+
+/* This function is called only via the WAS_NEWLINE macro, which does so only
+when the newline type is NLTYPE_ANY or NLTYPE_ANYCRLF. The case of a fixed
+newline (NLTYPE_FIXED) is handled inline. It is guaranteed that the initial
+value of ptr is greater than the start of the string that is being processed.
+
+Arguments:
+ ptr pointer to possible newline
+ type the newline type
+ startptr pointer to the start of the string
+ lenptr where to return the length
+ utf TRUE if in utf mode
+
+Returns: TRUE or FALSE
+*/
+
+BOOL
+PRIV(was_newline)(PCRE2_SPTR ptr, uint32_t type, PCRE2_SPTR startptr,
+ uint32_t *lenptr, BOOL utf)
+{
+uint32_t c;
+ptr--;
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+ {
+ BACKCHAR(ptr);
+ GETCHAR(c, ptr);
+ }
+else c = *ptr;
+#else
+(void)utf;
+c = *ptr;
+#endif /* SUPPORT_UNICODE */
+
+if (type == NLTYPE_ANYCRLF) switch(c)
+ {
+ case CHAR_LF:
+ *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
+ return TRUE;
+
+ case CHAR_CR:
+ *lenptr = 1;
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
+/* NLTYPE_ANY */
+
+else switch(c)
+ {
+ case CHAR_LF:
+ *lenptr = (ptr > startptr && ptr[-1] == CHAR_CR)? 2 : 1;
+ return TRUE;
+
+#ifdef EBCDIC
+ case CHAR_NEL:
+#endif
+ case CHAR_VT:
+ case CHAR_FF:
+ case CHAR_CR:
+ *lenptr = 1;
+ return TRUE;
+
+#ifndef EBCDIC
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ case CHAR_NEL:
+ *lenptr = utf? 2 : 1;
+ return TRUE;
+
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 3;
+ return TRUE;
+
+#else /* 16-bit or 32-bit code units */
+ case CHAR_NEL:
+ case 0x2028: /* LS */
+ case 0x2029: /* PS */
+ *lenptr = 1;
+ return TRUE;
+#endif
+#endif /* Not EBCDIC */
+
+ default:
+ return FALSE;
+ }
+}
+
+/* End of pcre2_newline.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_ord2utf.c b/test/monniaux/pcre2-10.32/pcre2_ord2utf.c
new file mode 100644
index 00000000..14037309
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_ord2utf.c
@@ -0,0 +1,120 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This file contains a function that converts a Unicode character code point
+into a UTF string. The behaviour is different for each code unit width. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/* If SUPPORT_UNICODE is not defined, this function will never be called.
+Supply a dummy function because some compilers do not like empty source
+modules. */
+
+#ifndef SUPPORT_UNICODE
+unsigned int
+PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
+{
+(void)(cvalue);
+(void)(buffer);
+return 0;
+}
+#else /* SUPPORT_UNICODE */
+
+
+/*************************************************
+* Convert code point to UTF *
+*************************************************/
+
+/*
+Arguments:
+ cvalue the character value
+ buffer pointer to buffer for result
+
+Returns: number of code units placed in the buffer
+*/
+
+unsigned int
+PRIV(ord2utf)(uint32_t cvalue, PCRE2_UCHAR *buffer)
+{
+/* Convert to UTF-8 */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+int i, j;
+for (i = 0; i < PRIV(utf8_table1_size); i++)
+ if ((int)cvalue <= PRIV(utf8_table1)[i]) break;
+buffer += i;
+for (j = i; j > 0; j--)
+ {
+ *buffer-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*buffer = PRIV(utf8_table2)[i] | cvalue;
+return i + 1;
+
+/* Convert to UTF-16 */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+if (cvalue <= 0xffff)
+ {
+ *buffer = (PCRE2_UCHAR)cvalue;
+ return 1;
+ }
+cvalue -= 0x10000;
+*buffer++ = 0xd800 | (cvalue >> 10);
+*buffer = 0xdc00 | (cvalue & 0x3ff);
+return 2;
+
+/* Convert to UTF-32 */
+
+#else
+*buffer = (PCRE2_UCHAR)cvalue;
+return 1;
+#endif
+}
+#endif /* SUPPORT_UNICODE */
+
+/* End of pcre_ord2utf.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_pattern_info.c b/test/monniaux/pcre2-10.32/pcre2_pattern_info.c
new file mode 100644
index 00000000..a29f5eff
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_pattern_info.c
@@ -0,0 +1,432 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Return info about compiled pattern *
+*************************************************/
+
+/*
+Arguments:
+ code points to compiled code
+ what what information is required
+ where where to put the information; if NULL, return length
+
+Returns: 0 when data returned
+ > 0 when length requested
+ < 0 on error or unset value
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_pattern_info(const pcre2_code *code, uint32_t what, void *where)
+{
+const pcre2_real_code *re = (pcre2_real_code *)code;
+
+if (where == NULL) /* Requests field length */
+ {
+ switch(what)
+ {
+ case PCRE2_INFO_ALLOPTIONS:
+ case PCRE2_INFO_ARGOPTIONS:
+ case PCRE2_INFO_BACKREFMAX:
+ case PCRE2_INFO_BSR:
+ case PCRE2_INFO_CAPTURECOUNT:
+ case PCRE2_INFO_DEPTHLIMIT:
+ case PCRE2_INFO_EXTRAOPTIONS:
+ case PCRE2_INFO_FIRSTCODETYPE:
+ case PCRE2_INFO_FIRSTCODEUNIT:
+ case PCRE2_INFO_HASBACKSLASHC:
+ case PCRE2_INFO_HASCRORLF:
+ case PCRE2_INFO_HEAPLIMIT:
+ case PCRE2_INFO_JCHANGED:
+ case PCRE2_INFO_LASTCODETYPE:
+ case PCRE2_INFO_LASTCODEUNIT:
+ case PCRE2_INFO_MATCHEMPTY:
+ case PCRE2_INFO_MATCHLIMIT:
+ case PCRE2_INFO_MAXLOOKBEHIND:
+ case PCRE2_INFO_MINLENGTH:
+ case PCRE2_INFO_NAMEENTRYSIZE:
+ case PCRE2_INFO_NAMECOUNT:
+ case PCRE2_INFO_NEWLINE:
+ return sizeof(uint32_t);
+
+ case PCRE2_INFO_FIRSTBITMAP:
+ return sizeof(const uint8_t *);
+
+ case PCRE2_INFO_JITSIZE:
+ case PCRE2_INFO_SIZE:
+ case PCRE2_INFO_FRAMESIZE:
+ return sizeof(size_t);
+
+ case PCRE2_INFO_NAMETABLE:
+ return sizeof(PCRE2_SPTR);
+ }
+ }
+
+if (re == NULL) return PCRE2_ERROR_NULL;
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check that this pattern was compiled in the correct bit mode */
+
+if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
+
+switch(what)
+ {
+ case PCRE2_INFO_ALLOPTIONS:
+ *((uint32_t *)where) = re->overall_options;
+ break;
+
+ case PCRE2_INFO_ARGOPTIONS:
+ *((uint32_t *)where) = re->compile_options;
+ break;
+
+ case PCRE2_INFO_BACKREFMAX:
+ *((uint32_t *)where) = re->top_backref;
+ break;
+
+ case PCRE2_INFO_BSR:
+ *((uint32_t *)where) = re->bsr_convention;
+ break;
+
+ case PCRE2_INFO_CAPTURECOUNT:
+ *((uint32_t *)where) = re->top_bracket;
+ break;
+
+ case PCRE2_INFO_DEPTHLIMIT:
+ *((uint32_t *)where) = re->limit_depth;
+ if (re->limit_depth == UINT32_MAX) return PCRE2_ERROR_UNSET;
+ break;
+
+ case PCRE2_INFO_EXTRAOPTIONS:
+ *((uint32_t *)where) = re->extra_options;
+ break;
+
+ case PCRE2_INFO_FIRSTCODETYPE:
+ *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)? 1 :
+ ((re->flags & PCRE2_STARTLINE) != 0)? 2 : 0;
+ break;
+
+ case PCRE2_INFO_FIRSTCODEUNIT:
+ *((uint32_t *)where) = ((re->flags & PCRE2_FIRSTSET) != 0)?
+ re->first_codeunit : 0;
+ break;
+
+ case PCRE2_INFO_FIRSTBITMAP:
+ *((const uint8_t **)where) = ((re->flags & PCRE2_FIRSTMAPSET) != 0)?
+ &(re->start_bitmap[0]) : NULL;
+ break;
+
+ case PCRE2_INFO_FRAMESIZE:
+ *((size_t *)where) = offsetof(heapframe, ovector) +
+ re->top_bracket * 2 * sizeof(PCRE2_SIZE);
+ break;
+
+ case PCRE2_INFO_HASBACKSLASHC:
+ *((uint32_t *)where) = (re->flags & PCRE2_HASBKC) != 0;
+ break;
+
+ case PCRE2_INFO_HASCRORLF:
+ *((uint32_t *)where) = (re->flags & PCRE2_HASCRORLF) != 0;
+ break;
+
+ case PCRE2_INFO_HEAPLIMIT:
+ *((uint32_t *)where) = re->limit_heap;
+ if (re->limit_heap == UINT32_MAX) return PCRE2_ERROR_UNSET;
+ break;
+
+ case PCRE2_INFO_JCHANGED:
+ *((uint32_t *)where) = (re->flags & PCRE2_JCHANGED) != 0;
+ break;
+
+ case PCRE2_INFO_JITSIZE:
+#ifdef SUPPORT_JIT
+ *((size_t *)where) = (re->executable_jit != NULL)?
+ PRIV(jit_get_size)(re->executable_jit) : 0;
+#else
+ *((size_t *)where) = 0;
+#endif
+ break;
+
+ case PCRE2_INFO_LASTCODETYPE:
+ *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)? 1 : 0;
+ break;
+
+ case PCRE2_INFO_LASTCODEUNIT:
+ *((uint32_t *)where) = ((re->flags & PCRE2_LASTSET) != 0)?
+ re->last_codeunit : 0;
+ break;
+
+ case PCRE2_INFO_MATCHEMPTY:
+ *((uint32_t *)where) = (re->flags & PCRE2_MATCH_EMPTY) != 0;
+ break;
+
+ case PCRE2_INFO_MATCHLIMIT:
+ *((uint32_t *)where) = re->limit_match;
+ if (re->limit_match == UINT32_MAX) return PCRE2_ERROR_UNSET;
+ break;
+
+ case PCRE2_INFO_MAXLOOKBEHIND:
+ *((uint32_t *)where) = re->max_lookbehind;
+ break;
+
+ case PCRE2_INFO_MINLENGTH:
+ *((uint32_t *)where) = re->minlength;
+ break;
+
+ case PCRE2_INFO_NAMEENTRYSIZE:
+ *((uint32_t *)where) = re->name_entry_size;
+ break;
+
+ case PCRE2_INFO_NAMECOUNT:
+ *((uint32_t *)where) = re->name_count;
+ break;
+
+ case PCRE2_INFO_NAMETABLE:
+ *((PCRE2_SPTR *)where) = (PCRE2_SPTR)((char *)re + sizeof(pcre2_real_code));
+ break;
+
+ case PCRE2_INFO_NEWLINE:
+ *((uint32_t *)where) = re->newline_convention;
+ break;
+
+ case PCRE2_INFO_SIZE:
+ *((size_t *)where) = re->blocksize;
+ break;
+
+ default: return PCRE2_ERROR_BADOPTION;
+ }
+
+return 0;
+}
+
+
+
+/*************************************************
+* Callout enumerator *
+*************************************************/
+
+/*
+Arguments:
+ code points to compiled code
+ callback function called for each callout block
+ callout_data user data passed to the callback
+
+Returns: 0 when successfully completed
+ < 0 on local error
+ != 0 for callback error
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_callout_enumerate(const pcre2_code *code,
+ int (*callback)(pcre2_callout_enumerate_block *, void *), void *callout_data)
+{
+pcre2_real_code *re = (pcre2_real_code *)code;
+pcre2_callout_enumerate_block cb;
+PCRE2_SPTR cc;
+#ifdef SUPPORT_UNICODE
+BOOL utf;
+#endif
+
+if (re == NULL) return PCRE2_ERROR_NULL;
+
+#ifdef SUPPORT_UNICODE
+utf = (re->overall_options & PCRE2_UTF) != 0;
+#endif
+
+/* Check that the first field in the block is the magic number. If it is not,
+return with PCRE2_ERROR_BADMAGIC. */
+
+if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+
+/* Check that this pattern was compiled in the correct bit mode */
+
+if ((re->flags & (PCRE2_CODE_UNIT_WIDTH/8)) == 0) return PCRE2_ERROR_BADMODE;
+
+cb.version = 0;
+cc = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code))
+ + re->name_count * re->name_entry_size;
+
+while (TRUE)
+ {
+ int rc;
+ switch (*cc)
+ {
+ case OP_END:
+ return 0;
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_EXACT:
+ case OP_POSSTAR:
+ case OP_POSPLUS:
+ case OP_POSQUERY:
+ case OP_POSUPTO:
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_EXACTI:
+ case OP_POSSTARI:
+ case OP_POSPLUSI:
+ case OP_POSQUERYI:
+ case OP_POSUPTOI:
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTEXACT:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSUPTO:
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTEXACTI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSUPTOI:
+ cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEEXACT:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEPOSQUERY:
+ case OP_TYPEPOSUPTO:
+ cc += PRIV(OP_lengths)[*cc];
+#ifdef SUPPORT_UNICODE
+ if (cc[-1] == OP_PROP || cc[-1] == OP_NOTPROP) cc += 2;
+#endif
+ break;
+
+#if defined SUPPORT_UNICODE || PCRE2_CODE_UNIT_WIDTH != 8
+ case OP_XCLASS:
+ cc += GET(cc, 1);
+ break;
+#endif
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ cc += PRIV(OP_lengths)[*cc] + cc[1];
+ break;
+
+ case OP_CALLOUT:
+ cb.pattern_position = GET(cc, 1);
+ cb.next_item_length = GET(cc, 1 + LINK_SIZE);
+ cb.callout_number = cc[1 + 2*LINK_SIZE];
+ cb.callout_string_offset = 0;
+ cb.callout_string_length = 0;
+ cb.callout_string = NULL;
+ rc = callback(&cb, callout_data);
+ if (rc != 0) return rc;
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+
+ case OP_CALLOUT_STR:
+ cb.pattern_position = GET(cc, 1);
+ cb.next_item_length = GET(cc, 1 + LINK_SIZE);
+ cb.callout_number = 0;
+ cb.callout_string_offset = GET(cc, 1 + 3*LINK_SIZE);
+ cb.callout_string_length =
+ GET(cc, 1 + 2*LINK_SIZE) - (1 + 4*LINK_SIZE) - 2;
+ cb.callout_string = cc + (1 + 4*LINK_SIZE) + 1;
+ rc = callback(&cb, callout_data);
+ if (rc != 0) return rc;
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
+ default:
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+ }
+ }
+}
+
+/* End of pcre2_pattern_info.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_printint.c b/test/monniaux/pcre2-10.32/pcre2_printint.c
new file mode 100644
index 00000000..bd10c6b1
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_printint.c
@@ -0,0 +1,832 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains a PCRE private debugging function for printing out the
+internal form of a compiled regular expression, along with some supporting
+local functions. This source file is #included in pcre2test.c at each supported
+code unit width, with PCRE2_SUFFIX set appropriately, just like the functions
+that comprise the library. It can also optionally be included in
+pcre2_compile.c for detailed debugging in error situations. */
+
+
+/* Tables of operator names. The same 8-bit table is used for all code unit
+widths, so it must be defined only once. The list itself is defined in
+pcre2_internal.h, which is #included by pcre2test before this file. */
+
+#ifndef OP_LISTS_DEFINED
+static const char *OP_names[] = { OP_NAME_LIST };
+#define OP_LISTS_DEFINED
+#endif
+
+/* The functions and tables herein must all have mode-dependent names. */
+
+#define OP_lengths PCRE2_SUFFIX(OP_lengths_)
+#define get_ucpname PCRE2_SUFFIX(get_ucpname_)
+#define pcre2_printint PCRE2_SUFFIX(pcre2_printint_)
+#define print_char PCRE2_SUFFIX(print_char_)
+#define print_custring PCRE2_SUFFIX(print_custring_)
+#define print_custring_bylen PCRE2_SUFFIX(print_custring_bylen_)
+#define print_prop PCRE2_SUFFIX(print_prop_)
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in pcre2_internal.h.
+The contents of the table are, however, mode-dependent. */
+
+static const uint8_t OP_lengths[] = { OP_LENGTHS };
+
+
+
+/*************************************************
+* Print one character from a string *
+*************************************************/
+
+/* In UTF mode the character may occupy more than one code unit.
+
+Arguments:
+ f file to write to
+ ptr pointer to first code unit of the character
+ utf TRUE if string is UTF (will be FALSE if UTF is not supported)
+
+Returns: number of additional code units used
+*/
+
+static unsigned int
+print_char(FILE *f, PCRE2_SPTR ptr, BOOL utf)
+{
+uint32_t c = *ptr;
+BOOL one_code_unit = !utf;
+
+/* If UTF is supported and requested, check for a valid single code unit. */
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ one_code_unit = c < 0x80;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ one_code_unit = (c & 0xfc00) != 0xd800;
+#else
+ one_code_unit = (c & 0xfffff800u) != 0xd800u;
+#endif /* CODE_UNIT_WIDTH */
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* Handle a valid one-code-unit character at any width. */
+
+if (one_code_unit)
+ {
+ if (PRINTABLE(c)) fprintf(f, "%c", (char)c);
+ else if (c < 0x80) fprintf(f, "\\x%02x", c);
+ else fprintf(f, "\\x{%02x}", c);
+ return 0;
+ }
+
+/* Code for invalid UTF code units and multi-unit UTF characters is different
+for each width. If UTF is not supported, control should never get here, but we
+need a return statement to keep the compiler happy. */
+
+#ifndef SUPPORT_UNICODE
+return 0;
+#else
+
+/* Malformed UTF-8 should occur only if the sanity check has been turned off.
+Rather than swallow random bytes, just stop if we hit a bad one. Print it with
+\X instead of \x as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+if ((c & 0xc0) != 0xc0)
+ {
+ fprintf(f, "\\X{%x}", c); /* Invalid starting byte */
+ return 0;
+ }
+else
+ {
+ int i;
+ int a = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes */
+ int s = 6*a;
+ c = (c & PRIV(utf8_table3)[a]) << s;
+ for (i = 1; i <= a; i++)
+ {
+ if ((ptr[i] & 0xc0) != 0x80)
+ {
+ fprintf(f, "\\X{%x}", c); /* Invalid secondary byte */
+ return i - 1;
+ }
+ s -= 6;
+ c |= (ptr[i] & 0x3f) << s;
+ }
+ fprintf(f, "\\x{%x}", c);
+ return a;
+}
+#endif /* PCRE2_CODE_UNIT_WIDTH == 8 */
+
+/* UTF-16: rather than swallow a low surrogate, just stop if we hit a bad one.
+Print it with \X instead of \x as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 16
+if ((ptr[1] & 0xfc00) != 0xdc00)
+ {
+ fprintf(f, "\\X{%x}", c);
+ return 0;
+ }
+c = (((c & 0x3ff) << 10) | (ptr[1] & 0x3ff)) + 0x10000;
+fprintf(f, "\\x{%x}", c);
+return 1;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 16 */
+
+/* For UTF-32 we get here only for a malformed code unit, which should only
+occur if the sanity check has been turned off. Print it with \X instead of \x
+as an indication. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+fprintf(f, "\\X{%x}", c);
+return 0;
+#endif /* PCRE2_CODE_UNIT_WIDTH == 32 */
+#endif /* SUPPORT_UNICODE */
+}
+
+
+
+/*************************************************
+* Print string as a list of code units *
+*************************************************/
+
+/* These take no account of UTF as they always print each individual code unit.
+The string is zero-terminated for print_custring(); the length is given for
+print_custring_bylen().
+
+Arguments:
+ f file to write to
+ ptr point to the string
+ len length for print_custring_bylen()
+
+Returns: nothing
+*/
+
+static void
+print_custring(FILE *f, PCRE2_SPTR ptr)
+{
+while (*ptr != '\0')
+ {
+ uint32_t c = *ptr++;
+ if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
+ }
+}
+
+static void
+print_custring_bylen(FILE *f, PCRE2_SPTR ptr, PCRE2_UCHAR len)
+{
+for (; len > 0; len--)
+ {
+ uint32_t c = *ptr++;
+ if (PRINTABLE(c)) fprintf(f, "%c", c); else fprintf(f, "\\x{%x}", c);
+ }
+}
+
+
+
+/*************************************************
+* Find Unicode property name *
+*************************************************/
+
+/* When there is no UTF/UCP support, the table of names does not exist. This
+function should not be called in such configurations, because a pattern that
+tries to use Unicode properties won't compile. Rather than put lots of #ifdefs
+into the main code, however, we just put one into this function. */
+
+static const char *
+get_ucpname(unsigned int ptype, unsigned int pvalue)
+{
+#ifdef SUPPORT_UNICODE
+int i;
+for (i = PRIV(utt_size) - 1; i >= 0; i--)
+ {
+ if (ptype == PRIV(utt)[i].type && pvalue == PRIV(utt)[i].value) break;
+ }
+return (i >= 0)? PRIV(utt_names) + PRIV(utt)[i].name_offset : "??";
+#else /* No UTF support */
+(void)ptype;
+(void)pvalue;
+return "??";
+#endif /* SUPPORT_UNICODE */
+}
+
+
+
+/*************************************************
+* Print Unicode property value *
+*************************************************/
+
+/* "Normal" properties can be printed from tables. The PT_CLIST property is a
+pseudo-property that contains a pointer to a list of case-equivalent
+characters.
+
+Arguments:
+ f file to write to
+ code pointer in the compiled code
+ before text to print before
+ after text to print after
+
+Returns: nothing
+*/
+
+static void
+print_prop(FILE *f, PCRE2_SPTR code, const char *before, const char *after)
+{
+if (code[1] != PT_CLIST)
+ {
+ fprintf(f, "%s%s %s%s", before, OP_names[*code], get_ucpname(code[1],
+ code[2]), after);
+ }
+else
+ {
+ const char *not = (*code == OP_PROP)? "" : "not ";
+ const uint32_t *p = PRIV(ucd_caseless_sets) + code[2];
+ fprintf (f, "%s%sclist", before, not);
+ while (*p < NOTACHAR) fprintf(f, " %04x", *p++);
+ fprintf(f, "%s", after);
+ }
+}
+
+
+
+/*************************************************
+* Print compiled pattern *
+*************************************************/
+
+/* The print_lengths flag controls whether offsets and lengths of items are
+printed. Lenths can be turned off from pcre2test so that automatic tests on
+bytecode can be written that do not depend on the value of LINK_SIZE.
+
+Arguments:
+ re a compiled pattern
+ f the file to write to
+ print_lengths show various lengths
+
+Returns: nothing
+*/
+
+static void
+pcre2_printint(pcre2_code *re, FILE *f, BOOL print_lengths)
+{
+PCRE2_SPTR codestart, nametable, code;
+uint32_t nesize = re->name_entry_size;
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+
+nametable = (PCRE2_SPTR)((uint8_t *)re + sizeof(pcre2_real_code));
+code = codestart = nametable + re->name_count * re->name_entry_size;
+
+for(;;)
+ {
+ PCRE2_SPTR ccode;
+ uint32_t c;
+ int i;
+ const char *flag = " ";
+ unsigned int extra = 0;
+
+ if (print_lengths)
+ fprintf(f, "%3d ", (int)(code - codestart));
+ else
+ fprintf(f, " ");
+
+ switch(*code)
+ {
+/* ========================================================================== */
+ /* These cases are never obeyed. This is a fudge that causes a compile-
+ time error if the vectors OP_names or OP_lengths, which are indexed
+ by opcode, are not the correct length. It seems to be the only way to do
+ such a check at compile time, as the sizeof() operator does not work in
+ the C preprocessor. */
+
+ case OP_TABLE_LENGTH:
+ case OP_TABLE_LENGTH +
+ ((sizeof(OP_names)/sizeof(const char *) == OP_TABLE_LENGTH) &&
+ (sizeof(OP_lengths) == OP_TABLE_LENGTH)):
+ return;
+/* ========================================================================== */
+
+ case OP_END:
+ fprintf(f, " %s\n", OP_names[*code]);
+ fprintf(f, "------------------------------------------------------------------\n");
+ return;
+
+ case OP_CHAR:
+ fprintf(f, " ");
+ do
+ {
+ code++;
+ code += 1 + print_char(f, code, utf);
+ }
+ while (*code == OP_CHAR);
+ fprintf(f, "\n");
+ continue;
+
+ case OP_CHARI:
+ fprintf(f, " /i ");
+ do
+ {
+ code++;
+ code += 1 + print_char(f, code, utf);
+ }
+ while (*code == OP_CHARI);
+ fprintf(f, "\n");
+ continue;
+
+ case OP_CBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRA:
+ case OP_SCBRAPOS:
+ if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+ else fprintf(f, " ");
+ fprintf(f, "%s %d", OP_names[*code], GET2(code, 1+LINK_SIZE));
+ break;
+
+ case OP_BRA:
+ case OP_BRAPOS:
+ case OP_SBRA:
+ case OP_SBRAPOS:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ case OP_ALT:
+ case OP_KET:
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ case OP_ONCE:
+ case OP_COND:
+ case OP_SCOND:
+ case OP_REVERSE:
+ if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+ else fprintf(f, " ");
+ fprintf(f, "%s", OP_names[*code]);
+ break;
+
+ case OP_CLOSE:
+ fprintf(f, " %s %d", OP_names[*code], GET2(code, 1));
+ break;
+
+ case OP_CREF:
+ fprintf(f, "%3d %s", GET2(code,1), OP_names[*code]);
+ break;
+
+ case OP_DNCREF:
+ {
+ PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+ fprintf(f, " %s Cond ref <", flag);
+ print_custring(f, entry);
+ fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+ }
+ break;
+
+ case OP_RREF:
+ c = GET2(code, 1);
+ if (c == RREF_ANY)
+ fprintf(f, " Cond recurse any");
+ else
+ fprintf(f, " Cond recurse %d", c);
+ break;
+
+ case OP_DNRREF:
+ {
+ PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+ fprintf(f, " %s Cond recurse <", flag);
+ print_custring(f, entry);
+ fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+ }
+ break;
+
+ case OP_FALSE:
+ fprintf(f, " Cond false");
+ break;
+
+ case OP_TRUE:
+ fprintf(f, " Cond true");
+ break;
+
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_POSSTARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_POSQUERYI:
+ flag = "/i";
+ /* Fall through */
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_POSSTAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_POSQUERY:
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSQUERY:
+ fprintf(f, " %s ", flag);
+
+ if (*code >= OP_TYPESTAR)
+ {
+ if (code[1] == OP_PROP || code[1] == OP_NOTPROP)
+ {
+ print_prop(f, code + 1, "", " ");
+ extra = 2;
+ }
+ else fprintf(f, "%s", OP_names[code[1]]);
+ }
+ else extra = print_char(f, code+1, utf);
+ fprintf(f, "%s", OP_names[*code]);
+ break;
+
+ case OP_EXACTI:
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_POSUPTOI:
+ flag = "/i";
+ /* Fall through */
+ case OP_EXACT:
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
+ fprintf(f, " %s ", flag);
+ extra = print_char(f, code + 1 + IMM2_SIZE, utf);
+ fprintf(f, "{");
+ if (*code != OP_EXACT && *code != OP_EXACTI) fprintf(f, "0,");
+ fprintf(f, "%d}", GET2(code,1));
+ if (*code == OP_MINUPTO || *code == OP_MINUPTOI) fprintf(f, "?");
+ else if (*code == OP_POSUPTO || *code == OP_POSUPTOI) fprintf(f, "+");
+ break;
+
+ case OP_TYPEEXACT:
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ if (code[1 + IMM2_SIZE] == OP_PROP || code[1 + IMM2_SIZE] == OP_NOTPROP)
+ {
+ print_prop(f, code + IMM2_SIZE + 1, " ", " ");
+ extra = 2;
+ }
+ else fprintf(f, " %s", OP_names[code[1 + IMM2_SIZE]]);
+ fprintf(f, "{");
+ if (*code != OP_TYPEEXACT) fprintf(f, "0,");
+ fprintf(f, "%d}", GET2(code,1));
+ if (*code == OP_TYPEMINUPTO) fprintf(f, "?");
+ else if (*code == OP_TYPEPOSUPTO) fprintf(f, "+");
+ break;
+
+ case OP_NOTI:
+ flag = "/i";
+ /* Fall through */
+ case OP_NOT:
+ fprintf(f, " %s [^", flag);
+ extra = print_char(f, code + 1, utf);
+ fprintf(f, "]");
+ break;
+
+ case OP_NOTSTARI:
+ case OP_NOTMINSTARI:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTQUERYI:
+ case OP_NOTMINQUERYI:
+ case OP_NOTPOSQUERYI:
+ flag = "/i";
+ /* Fall through */
+
+ case OP_NOTSTAR:
+ case OP_NOTMINSTAR:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPLUS:
+ case OP_NOTMINPLUS:
+ case OP_NOTPOSPLUS:
+ case OP_NOTQUERY:
+ case OP_NOTMINQUERY:
+ case OP_NOTPOSQUERY:
+ fprintf(f, " %s [^", flag);
+ extra = print_char(f, code + 1, utf);
+ fprintf(f, "]%s", OP_names[*code]);
+ break;
+
+ case OP_NOTEXACTI:
+ case OP_NOTUPTOI:
+ case OP_NOTMINUPTOI:
+ case OP_NOTPOSUPTOI:
+ flag = "/i";
+ /* Fall through */
+
+ case OP_NOTEXACT:
+ case OP_NOTUPTO:
+ case OP_NOTMINUPTO:
+ case OP_NOTPOSUPTO:
+ fprintf(f, " %s [^", flag);
+ extra = print_char(f, code + 1 + IMM2_SIZE, utf);
+ fprintf(f, "]{");
+ if (*code != OP_NOTEXACT && *code != OP_NOTEXACTI) fprintf(f, "0,");
+ fprintf(f, "%d}", GET2(code,1));
+ if (*code == OP_NOTMINUPTO || *code == OP_NOTMINUPTOI) fprintf(f, "?");
+ else
+ if (*code == OP_NOTPOSUPTO || *code == OP_NOTPOSUPTOI) fprintf(f, "+");
+ break;
+
+ case OP_RECURSE:
+ if (print_lengths) fprintf(f, "%3d ", GET(code, 1));
+ else fprintf(f, " ");
+ fprintf(f, "%s", OP_names[*code]);
+ break;
+
+ case OP_REFI:
+ flag = "/i";
+ /* Fall through */
+ case OP_REF:
+ fprintf(f, " %s \\%d", flag, GET2(code,1));
+ ccode = code + OP_lengths[*code];
+ goto CLASS_REF_REPEAT;
+
+ case OP_DNREFI:
+ flag = "/i";
+ /* Fall through */
+ case OP_DNREF:
+ {
+ PCRE2_SPTR entry = nametable + (GET2(code, 1) * nesize) + IMM2_SIZE;
+ fprintf(f, " %s \\k<", flag);
+ print_custring(f, entry);
+ fprintf(f, ">%d", GET2(code, 1 + IMM2_SIZE));
+ }
+ ccode = code + OP_lengths[*code];
+ goto CLASS_REF_REPEAT;
+
+ case OP_CALLOUT:
+ fprintf(f, " %s %d %d %d", OP_names[*code], code[1 + 2*LINK_SIZE],
+ GET(code, 1), GET(code, 1 + LINK_SIZE));
+ break;
+
+ case OP_CALLOUT_STR:
+ c = code[1 + 4*LINK_SIZE];
+ fprintf(f, " %s %c", OP_names[*code], c);
+ extra = GET(code, 1 + 2*LINK_SIZE);
+ print_custring_bylen(f, code + 2 + 4*LINK_SIZE, extra - 3 - 4*LINK_SIZE);
+ for (i = 0; PRIV(callout_start_delims)[i] != 0; i++)
+ if (c == PRIV(callout_start_delims)[i])
+ {
+ c = PRIV(callout_end_delims)[i];
+ break;
+ }
+ fprintf(f, "%c %d %d %d", c, GET(code, 1 + 3*LINK_SIZE), GET(code, 1),
+ GET(code, 1 + LINK_SIZE));
+ break;
+
+ case OP_PROP:
+ case OP_NOTPROP:
+ print_prop(f, code, " ", "");
+ break;
+
+ /* OP_XCLASS cannot occur in 8-bit, non-UTF mode. However, there's no harm
+ in having this code always here, and it makes it less messy without all
+ those #ifdefs. */
+
+ case OP_CLASS:
+ case OP_NCLASS:
+ case OP_XCLASS:
+ {
+ unsigned int min, max;
+ BOOL printmap;
+ BOOL invertmap = FALSE;
+ uint8_t *map;
+ uint8_t inverted_map[32];
+
+ fprintf(f, " [");
+
+ if (*code == OP_XCLASS)
+ {
+ extra = GET(code, 1);
+ ccode = code + LINK_SIZE + 1;
+ printmap = (*ccode & XCL_MAP) != 0;
+ if ((*ccode & XCL_NOT) != 0)
+ {
+ invertmap = (*ccode & XCL_HASPROP) == 0;
+ fprintf(f, "^");
+ }
+ ccode++;
+ }
+ else
+ {
+ printmap = TRUE;
+ ccode = code + 1;
+ }
+
+ /* Print a bit map */
+
+ if (printmap)
+ {
+ map = (uint8_t *)ccode;
+ if (invertmap)
+ {
+ for (i = 0; i < 32; i++) inverted_map[i] = ~map[i];
+ map = inverted_map;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ if ((map[i/8] & (1 << (i&7))) != 0)
+ {
+ int j;
+ for (j = i+1; j < 256; j++)
+ if ((map[j/8] & (1 << (j&7))) == 0) break;
+ if (i == '-' || i == ']') fprintf(f, "\\");
+ if (PRINTABLE(i)) fprintf(f, "%c", i);
+ else fprintf(f, "\\x%02x", i);
+ if (--j > i)
+ {
+ if (j != i + 1) fprintf(f, "-");
+ if (j == '-' || j == ']') fprintf(f, "\\");
+ if (PRINTABLE(j)) fprintf(f, "%c", j);
+ else fprintf(f, "\\x%02x", j);
+ }
+ i = j;
+ }
+ }
+ ccode += 32 / sizeof(PCRE2_UCHAR);
+ }
+
+ /* For an XCLASS there is always some additional data */
+
+ if (*code == OP_XCLASS)
+ {
+ PCRE2_UCHAR ch;
+ while ((ch = *ccode++) != XCL_END)
+ {
+ BOOL not = FALSE;
+ const char *notch = "";
+
+ switch(ch)
+ {
+ case XCL_NOTPROP:
+ not = TRUE;
+ notch = "^";
+ /* Fall through */
+
+ case XCL_PROP:
+ {
+ unsigned int ptype = *ccode++;
+ unsigned int pvalue = *ccode++;
+
+ switch(ptype)
+ {
+ case PT_PXGRAPH:
+ fprintf(f, "[:%sgraph:]", notch);
+ break;
+
+ case PT_PXPRINT:
+ fprintf(f, "[:%sprint:]", notch);
+ break;
+
+ case PT_PXPUNCT:
+ fprintf(f, "[:%spunct:]", notch);
+ break;
+
+ default:
+ fprintf(f, "\\%c{%s}", (not? 'P':'p'),
+ get_ucpname(ptype, pvalue));
+ break;
+ }
+ }
+ break;
+
+ default:
+ ccode += 1 + print_char(f, ccode, utf);
+ if (ch == XCL_RANGE)
+ {
+ fprintf(f, "-");
+ ccode += 1 + print_char(f, ccode, utf);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Indicate a non-UTF class which was created by negation */
+
+ fprintf(f, "]%s", (*code == OP_NCLASS)? " (neg)" : "");
+
+ /* Handle repeats after a class or a back reference */
+
+ CLASS_REF_REPEAT:
+ switch(*ccode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSPLUS:
+ case OP_CRPOSQUERY:
+ fprintf(f, "%s", OP_names[*ccode]);
+ extra += OP_lengths[*ccode];
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ min = GET2(ccode,1);
+ max = GET2(ccode,1 + IMM2_SIZE);
+ if (max == 0) fprintf(f, "{%u,}", min);
+ else fprintf(f, "{%u,%u}", min, max);
+ if (*ccode == OP_CRMINRANGE) fprintf(f, "?");
+ else if (*ccode == OP_CRPOSRANGE) fprintf(f, "+");
+ extra += OP_lengths[*ccode];
+ break;
+
+ /* Do nothing if it's not a repeat; this code stops picky compilers
+ warning about the lack of a default code path. */
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ fprintf(f, " %s ", OP_names[*code]);
+ print_custring_bylen(f, code + 2, code[1]);
+ extra += code[1];
+ break;
+
+ case OP_THEN:
+ fprintf(f, " %s", OP_names[*code]);
+ break;
+
+ case OP_CIRCM:
+ case OP_DOLLM:
+ flag = "/m";
+ /* Fall through */
+
+ /* Anything else is just an item with no data, but possibly a flag. */
+
+ default:
+ fprintf(f, " %s %s", flag, OP_names[*code]);
+ break;
+ }
+
+ code += OP_lengths[*code] + extra;
+ fprintf(f, "\n");
+ }
+}
+
+/* End of pcre2_printint.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_serialize.c b/test/monniaux/pcre2-10.32/pcre2_serialize.c
new file mode 100644
index 00000000..cec1a035
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_serialize.c
@@ -0,0 +1,286 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions for serializing and deserializing
+a sequence of compiled codes. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+/* Magic number to provide a small check against being handed junk. */
+
+#define SERIALIZED_DATA_MAGIC 0x50523253u
+
+/* Deserialization is limited to the current PCRE version and
+character width. */
+
+#define SERIALIZED_DATA_VERSION \
+ ((PCRE2_MAJOR) | ((PCRE2_MINOR) << 16))
+
+#define SERIALIZED_DATA_CONFIG \
+ (sizeof(PCRE2_UCHAR) | ((sizeof(void*)) << 8) | ((sizeof(PCRE2_SIZE)) << 16))
+
+
+
+/*************************************************
+* Serialize compiled patterns *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_encode(const pcre2_code **codes, int32_t number_of_codes,
+ uint8_t **serialized_bytes, PCRE2_SIZE *serialized_size,
+ pcre2_general_context *gcontext)
+{
+uint8_t *bytes;
+uint8_t *dst_bytes;
+int32_t i;
+PCRE2_SIZE total_size;
+const pcre2_real_code *re;
+const uint8_t *tables;
+pcre2_serialized_data *data;
+
+const pcre2_memctl *memctl = (gcontext != NULL) ?
+ &gcontext->memctl : &PRIV(default_compile_context).memctl;
+
+if (codes == NULL || serialized_bytes == NULL || serialized_size == NULL)
+ return PCRE2_ERROR_NULL;
+
+if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
+
+/* Compute total size. */
+total_size = sizeof(pcre2_serialized_data) + tables_length;
+tables = NULL;
+
+for (i = 0; i < number_of_codes; i++)
+ {
+ if (codes[i] == NULL) return PCRE2_ERROR_NULL;
+ re = (const pcre2_real_code *)(codes[i]);
+ if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
+ if (tables == NULL)
+ tables = re->tables;
+ else if (tables != re->tables)
+ return PCRE2_ERROR_MIXEDTABLES;
+ total_size += re->blocksize;
+ }
+
+/* Initialize the byte stream. */
+bytes = memctl->malloc(total_size + sizeof(pcre2_memctl), memctl->memory_data);
+if (bytes == NULL) return PCRE2_ERROR_NOMEMORY;
+
+/* The controller is stored as a hidden parameter. */
+memcpy(bytes, memctl, sizeof(pcre2_memctl));
+bytes += sizeof(pcre2_memctl);
+
+data = (pcre2_serialized_data *)bytes;
+data->magic = SERIALIZED_DATA_MAGIC;
+data->version = SERIALIZED_DATA_VERSION;
+data->config = SERIALIZED_DATA_CONFIG;
+data->number_of_codes = number_of_codes;
+
+/* Copy all compiled code data. */
+dst_bytes = bytes + sizeof(pcre2_serialized_data);
+memcpy(dst_bytes, tables, tables_length);
+dst_bytes += tables_length;
+
+for (i = 0; i < number_of_codes; i++)
+ {
+ re = (const pcre2_real_code *)(codes[i]);
+ (void)memcpy(dst_bytes, (char *)re, re->blocksize);
+
+ /* Certain fields in the compiled code block are re-set during
+ deserialization. In order to ensure that the serialized data stream is always
+ the same for the same pattern, set them to zero here. We can't assume the
+ copy of the pattern is correctly aligned for accessing the fields as part of
+ a structure. Note the use of sizeof(void *) in the second of these, to
+ specify the size of a pointer. If sizeof(uint8_t *) is used (tables is a
+ pointer to uint8_t), gcc gives a warning because the first argument is also a
+ pointer to uint8_t. Casting the first argument to (void *) can stop this, but
+ it didn't stop Coverity giving the same complaint. */
+
+ (void)memset(dst_bytes + offsetof(pcre2_real_code, memctl), 0,
+ sizeof(pcre2_memctl));
+ (void)memset(dst_bytes + offsetof(pcre2_real_code, tables), 0,
+ sizeof(void *));
+ (void)memset(dst_bytes + offsetof(pcre2_real_code, executable_jit), 0,
+ sizeof(void *));
+
+ dst_bytes += re->blocksize;
+ }
+
+*serialized_bytes = bytes;
+*serialized_size = total_size;
+return number_of_codes;
+}
+
+
+/*************************************************
+* Deserialize compiled patterns *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_decode(pcre2_code **codes, int32_t number_of_codes,
+ const uint8_t *bytes, pcre2_general_context *gcontext)
+{
+const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
+const pcre2_memctl *memctl = (gcontext != NULL) ?
+ &gcontext->memctl : &PRIV(default_compile_context).memctl;
+
+const uint8_t *src_bytes;
+pcre2_real_code *dst_re;
+uint8_t *tables;
+int32_t i, j;
+
+/* Sanity checks. */
+
+if (data == NULL || codes == NULL) return PCRE2_ERROR_NULL;
+if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
+if (data->number_of_codes <= 0) return PCRE2_ERROR_BADSERIALIZEDDATA;
+if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
+if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
+if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
+
+if (number_of_codes > data->number_of_codes)
+ number_of_codes = data->number_of_codes;
+
+src_bytes = bytes + sizeof(pcre2_serialized_data);
+
+/* Decode tables. The reference count for the tables is stored immediately
+following them. */
+
+tables = memctl->malloc(tables_length + sizeof(PCRE2_SIZE), memctl->memory_data);
+if (tables == NULL) return PCRE2_ERROR_NOMEMORY;
+
+memcpy(tables, src_bytes, tables_length);
+*(PCRE2_SIZE *)(tables + tables_length) = number_of_codes;
+src_bytes += tables_length;
+
+/* Decode the byte stream. We must not try to read the size from the compiled
+code block in the stream, because it might be unaligned, which causes errors on
+hardware such as Sparc-64 that doesn't like unaligned memory accesses. The type
+of the blocksize field is given its own name to ensure that it is the same here
+as in the block. */
+
+for (i = 0; i < number_of_codes; i++)
+ {
+ CODE_BLOCKSIZE_TYPE blocksize;
+ memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize),
+ sizeof(CODE_BLOCKSIZE_TYPE));
+ if (blocksize <= sizeof(pcre2_real_code))
+ return PCRE2_ERROR_BADSERIALIZEDDATA;
+
+ /* The allocator provided by gcontext replaces the original one. */
+
+ dst_re = (pcre2_real_code *)PRIV(memctl_malloc)(blocksize,
+ (pcre2_memctl *)gcontext);
+ if (dst_re == NULL)
+ {
+ memctl->free(tables, memctl->memory_data);
+ for (j = 0; j < i; j++)
+ {
+ memctl->free(codes[j], memctl->memory_data);
+ codes[j] = NULL;
+ }
+ return PCRE2_ERROR_NOMEMORY;
+ }
+
+ /* The new allocator must be preserved. */
+
+ memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl),
+ src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl));
+ if (dst_re->magic_number != MAGIC_NUMBER ||
+ dst_re->name_entry_size > MAX_NAME_SIZE + IMM2_SIZE + 1 ||
+ dst_re->name_count > MAX_NAME_COUNT)
+ {
+ memctl->free(dst_re, memctl->memory_data);
+ return PCRE2_ERROR_BADSERIALIZEDDATA;
+ }
+
+ /* At the moment only one table is supported. */
+
+ dst_re->tables = tables;
+ dst_re->executable_jit = NULL;
+ dst_re->flags |= PCRE2_DEREF_TABLES;
+
+ codes[i] = dst_re;
+ src_bytes += blocksize;
+ }
+
+return number_of_codes;
+}
+
+
+/*************************************************
+* Get the number of serialized patterns *
+*************************************************/
+
+PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
+pcre2_serialize_get_number_of_codes(const uint8_t *bytes)
+{
+const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
+
+if (data == NULL) return PCRE2_ERROR_NULL;
+if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
+if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
+if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
+
+return data->number_of_codes;
+}
+
+
+/*************************************************
+* Free the allocated stream *
+*************************************************/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_serialize_free(uint8_t *bytes)
+{
+if (bytes != NULL)
+ {
+ pcre2_memctl *memctl = (pcre2_memctl *)(bytes - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+/* End of pcre2_serialize.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_string_utils.c b/test/monniaux/pcre2-10.32/pcre2_string_utils.c
new file mode 100644
index 00000000..d6be01ac
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_string_utils.c
@@ -0,0 +1,237 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains internal functions for comparing and finding the length
+of strings. These are used instead of strcmp() etc because the standard
+functions work only on 8-bit data. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+/*************************************************
+* Emulated memmove() for systems without it *
+*************************************************/
+
+/* This function can make use of bcopy() if it is available. Otherwise do it by
+steam, as there some non-Unix environments that lack both memmove() and
+bcopy(). */
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+void *
+PRIV(memmove)(void *d, const void *s, size_t n)
+{
+#ifdef HAVE_BCOPY
+bcopy(s, d, n);
+return d;
+#else
+size_t i;
+unsigned char *dest = (unsigned char *)d;
+const unsigned char *src = (const unsigned char *)s;
+if (dest > src)
+ {
+ dest += n;
+ src += n;
+ for (i = 0; i < n; ++i) *(--dest) = *(--src);
+ return (void *)dest;
+ }
+else
+ {
+ for (i = 0; i < n; ++i) *dest++ = *src++;
+ return (void *)(dest - n);
+ }
+#endif /* not HAVE_BCOPY */
+}
+#endif /* not VPCOMPAT && not HAVE_MEMMOVE */
+
+
+/*************************************************
+* Compare two zero-terminated PCRE2 strings *
+*************************************************/
+
+/*
+Arguments:
+ str1 first string
+ str2 second string
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strcmp)(PCRE2_SPTR str1, PCRE2_SPTR str2)
+{
+PCRE2_UCHAR c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Compare zero-terminated PCRE2 & 8-bit strings *
+*************************************************/
+
+/* As the 8-bit string is almost always a literal, its type is specified as
+const char *.
+
+Arguments:
+ str1 first string
+ str2 second string
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strcmp_c8)(PCRE2_SPTR str1, const char *str2)
+{
+PCRE2_UCHAR c1, c2;
+while (*str1 != '\0' || *str2 != '\0')
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Compare two PCRE2 strings, given a length *
+*************************************************/
+
+/*
+Arguments:
+ str1 first string
+ str2 second string
+ len the length
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strncmp)(PCRE2_SPTR str1, PCRE2_SPTR str2, size_t len)
+{
+PCRE2_UCHAR c1, c2;
+for (; len > 0; len--)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Compare PCRE2 string to 8-bit string by length *
+*************************************************/
+
+/* As the 8-bit string is almost always a literal, its type is specified as
+const char *.
+
+Arguments:
+ str1 first string
+ str2 second string
+ len the length
+
+Returns: 0, 1, or -1
+*/
+
+int
+PRIV(strncmp_c8)(PCRE2_SPTR str1, const char *str2, size_t len)
+{
+PCRE2_UCHAR c1, c2;
+for (; len > 0; len--)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2) return ((c1 > c2) << 1) - 1;
+ }
+return 0;
+}
+
+
+/*************************************************
+* Find the length of a PCRE2 string *
+*************************************************/
+
+/*
+Argument: the string
+Returns: the length
+*/
+
+PCRE2_SIZE
+PRIV(strlen)(PCRE2_SPTR str)
+{
+PCRE2_SIZE c = 0;
+while (*str++ != 0) c++;
+return c;
+}
+
+
+/*************************************************
+* Copy 8-bit 0-terminated string to PCRE2 string *
+*************************************************/
+
+/* Arguments:
+ str1 buffer to receive the string
+ str2 8-bit string to be copied
+
+Returns: the number of code units used (excluding trailing zero)
+*/
+
+PCRE2_SIZE
+PRIV(strcpy_c8)(PCRE2_UCHAR *str1, const char *str2)
+{
+PCRE2_UCHAR *t = str1;
+while (*str2 != 0) *t++ = *str2++;
+*t = 0;
+return t - str1;
+}
+
+/* End of pcre2_string_utils.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_study.c b/test/monniaux/pcre2-10.32/pcre2_study.c
new file mode 100644
index 00000000..acbf98b4
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_study.c
@@ -0,0 +1,1635 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains functions for scanning a compiled pattern and
+collecting data (e.g. minimum matching length). */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+/* The maximum remembered capturing brackets minimum. */
+
+#define MAX_CACHE_BACKREF 128
+
+/* Set a bit in the starting code unit bit map. */
+
+#define SET_BIT(c) re->start_bitmap[(c)/8] |= (1 << ((c)&7))
+
+/* Returns from set_start_bits() */
+
+enum { SSB_FAIL, SSB_DONE, SSB_CONTINUE, SSB_UNKNOWN };
+
+
+/*************************************************
+* Find the minimum subject length for a group *
+*************************************************/
+
+/* Scan a parenthesized group and compute the minimum length of subject that
+is needed to match it. This is a lower bound; it does not mean there is a
+string of that length that matches. In UTF mode, the result is in characters
+rather than code units. The field in a compiled pattern for storing the minimum
+length is 16-bits long (on the grounds that anything longer than that is
+pathological), so we give up when we reach that amount. This also means that
+integer overflow for really crazy patterns cannot happen.
+
+Backreference minimum lengths are cached to speed up multiple references. This
+function is called only when the highest back reference in the pattern is less
+than or equal to MAX_CACHE_BACKREF, which is one less than the size of the
+caching vector. The zeroth element contains the number of the highest set
+value.
+
+Arguments:
+ re compiled pattern block
+ code pointer to start of group (the bracket)
+ startcode pointer to start of the whole pattern's code
+ utf UTF flag
+ recurses chain of recurse_check to catch mutual recursion
+ countptr pointer to call count (to catch over complexity)
+ backref_cache vector for caching back references.
+
+Returns: the minimum length
+ -1 \C in UTF-8 mode
+ or (*ACCEPT)
+ or pattern too complicated
+ or back reference to duplicate name/number
+ -2 internal error (missing capturing bracket)
+ -3 internal error (opcode not listed)
+*/
+
+static int
+find_minlength(const pcre2_real_code *re, PCRE2_SPTR code,
+ PCRE2_SPTR startcode, BOOL utf, recurse_check *recurses, int *countptr,
+ int *backref_cache)
+{
+int length = -1;
+int prev_cap_recno = -1;
+int prev_cap_d = 0;
+int prev_recurse_recno = -1;
+int prev_recurse_d = 0;
+uint32_t once_fudge = 0;
+BOOL had_recurse = FALSE;
+BOOL dupcapused = (re->flags & PCRE2_DUPCAPUSED) != 0;
+recurse_check this_recurse;
+int branchlength = 0;
+PCRE2_UCHAR *cc = (PCRE2_UCHAR *)code + 1 + LINK_SIZE;
+
+/* If this is a "could be empty" group, its minimum length is 0. */
+
+if (*code >= OP_SBRA && *code <= OP_SCOND) return 0;
+
+/* Skip over capturing bracket number */
+
+if (*code == OP_CBRA || *code == OP_CBRAPOS) cc += IMM2_SIZE;
+
+/* A large and/or complex regex can take too long to process. */
+
+if ((*countptr)++ > 1000) return -1;
+
+/* Scan along the opcodes for this branch. If we get to the end of the branch,
+check the length against that of the other branches. If the accumulated length
+passes 16-bits, stop. */
+
+for (;;)
+ {
+ int d, min, recno;
+ PCRE2_UCHAR *cs, *ce;
+ PCRE2_UCHAR op = *cc;
+
+ if (branchlength >= UINT16_MAX) return UINT16_MAX;
+
+ switch (op)
+ {
+ case OP_COND:
+ case OP_SCOND:
+
+ /* If there is only one branch in a condition, the implied branch has zero
+ length, so we don't add anything. This covers the DEFINE "condition"
+ automatically. If there are two branches we can treat it the same as any
+ other non-capturing subpattern. */
+
+ cs = cc + GET(cc, 1);
+ if (*cs != OP_ALT)
+ {
+ cc = cs + 1 + LINK_SIZE;
+ break;
+ }
+ goto PROCESS_NON_CAPTURE;
+
+ case OP_BRA:
+ /* There's a special case of OP_BRA, when it is wrapped round a repeated
+ OP_RECURSE. We'd like to process the latter at this level so that
+ remembering the value works for repeated cases. So we do nothing, but
+ set a fudge value to skip over the OP_KET after the recurse. */
+
+ if (cc[1+LINK_SIZE] == OP_RECURSE && cc[2*(1+LINK_SIZE)] == OP_KET)
+ {
+ once_fudge = 1 + LINK_SIZE;
+ cc += 1 + LINK_SIZE;
+ break;
+ }
+ /* Fall through */
+
+ case OP_ONCE:
+ case OP_SBRA:
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ PROCESS_NON_CAPTURE:
+ d = find_minlength(re, cc, startcode, utf, recurses, countptr,
+ backref_cache);
+ if (d < 0) return d;
+ branchlength += d;
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* To save time for repeated capturing subpatterns, we remember the
+ length of the previous one. Unfortunately we can't do the same for
+ the unnumbered ones above. Nor can we do this if (?| is present in the
+ pattern because captures with the same number are not then identical. */
+
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ recno = (int)GET2(cc, 1+LINK_SIZE);
+ if (dupcapused || recno != prev_cap_recno)
+ {
+ prev_cap_recno = recno;
+ prev_cap_d = find_minlength(re, cc, startcode, utf, recurses, countptr,
+ backref_cache);
+ if (prev_cap_d < 0) return prev_cap_d;
+ }
+ branchlength += prev_cap_d;
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* ACCEPT makes things far too complicated; we have to give up. */
+
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ return -1;
+
+ /* Reached end of a branch; if it's a ket it is the end of a nested
+ call. If it's ALT it is an alternation in a nested call. If it is END it's
+ the end of the outer call. All can be handled by the same code. If an
+ ACCEPT was previously encountered, use the length that was in force at that
+ time, and pass back the shortest ACCEPT length. */
+
+ case OP_ALT:
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ case OP_END:
+ if (length < 0 || (!had_recurse && branchlength < length))
+ length = branchlength;
+ if (op != OP_ALT) return length;
+ cc += 1 + LINK_SIZE;
+ branchlength = 0;
+ had_recurse = FALSE;
+ break;
+
+ /* Skip over assertive subpatterns */
+
+ case OP_ASSERT:
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ /* Fall through */
+
+ /* Skip over things that don't match chars */
+
+ case OP_REVERSE:
+ case OP_CREF:
+ case OP_DNCREF:
+ case OP_RREF:
+ case OP_DNRREF:
+ case OP_FALSE:
+ case OP_TRUE:
+ case OP_CALLOUT:
+ case OP_SOD:
+ case OP_SOM:
+ case OP_EOD:
+ case OP_EODN:
+ case OP_CIRC:
+ case OP_CIRCM:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_NOT_WORD_BOUNDARY:
+ case OP_WORD_BOUNDARY:
+ cc += PRIV(OP_lengths)[*cc];
+ break;
+
+ case OP_CALLOUT_STR:
+ cc += GET(cc, 1 + 2*LINK_SIZE);
+ break;
+
+ /* Skip over a subpattern that has a {0} or {0,x} quantifier */
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ case OP_SKIPZERO:
+ cc += PRIV(OP_lengths)[*cc];
+ do cc += GET(cc, 1); while (*cc == OP_ALT);
+ cc += 1 + LINK_SIZE;
+ break;
+
+ /* Handle literal characters and + repetitions */
+
+ case OP_CHAR:
+ case OP_CHARI:
+ case OP_NOT:
+ case OP_NOTI:
+ case OP_PLUS:
+ case OP_PLUSI:
+ case OP_MINPLUS:
+ case OP_MINPLUSI:
+ case OP_POSPLUS:
+ case OP_POSPLUSI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ branchlength++;
+ cc += 2;
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ branchlength++;
+ cc += (cc[1] == OP_PROP || cc[1] == OP_NOTPROP)? 4 : 2;
+ break;
+
+ /* Handle exact repetitions. The count is already in characters, but we
+ may need to skip over a multibyte character in UTF mode. */
+
+ case OP_EXACT:
+ case OP_EXACTI:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ branchlength += GET2(cc,1);
+ cc += 2 + IMM2_SIZE;
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ case OP_TYPEEXACT:
+ branchlength += GET2(cc,1);
+ cc += 2 + IMM2_SIZE + ((cc[1 + IMM2_SIZE] == OP_PROP
+ || cc[1 + IMM2_SIZE] == OP_NOTPROP)? 2 : 0);
+ break;
+
+ /* Handle single-char non-literal matchers */
+
+ case OP_PROP:
+ case OP_NOTPROP:
+ cc += 2;
+ /* Fall through */
+
+ case OP_NOT_DIGIT:
+ case OP_DIGIT:
+ case OP_NOT_WHITESPACE:
+ case OP_WHITESPACE:
+ case OP_NOT_WORDCHAR:
+ case OP_WORDCHAR:
+ case OP_ANY:
+ case OP_ALLANY:
+ case OP_EXTUNI:
+ case OP_HSPACE:
+ case OP_NOT_HSPACE:
+ case OP_VSPACE:
+ case OP_NOT_VSPACE:
+ branchlength++;
+ cc++;
+ break;
+
+ /* "Any newline" might match two characters, but it also might match just
+ one. */
+
+ case OP_ANYNL:
+ branchlength += 1;
+ cc++;
+ break;
+
+ /* The single-byte matcher means we can't proceed in UTF mode. (In
+ non-UTF mode \C will actually be turned into OP_ALLANY, so won't ever
+ appear, but leave the code, just in case.) */
+
+ case OP_ANYBYTE:
+#ifdef SUPPORT_UNICODE
+ if (utf) return -1;
+#endif
+ branchlength++;
+ cc++;
+ break;
+
+ /* For repeated character types, we have to test for \p and \P, which have
+ an extra two bytes of parameters. */
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEPOSQUERY:
+ if (cc[1] == OP_PROP || cc[1] == OP_NOTPROP) cc += 2;
+ cc += PRIV(OP_lengths)[op];
+ break;
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ if (cc[1 + IMM2_SIZE] == OP_PROP
+ || cc[1 + IMM2_SIZE] == OP_NOTPROP) cc += 2;
+ cc += PRIV(OP_lengths)[op];
+ break;
+
+ /* Check a class for variable quantification */
+
+ case OP_CLASS:
+ case OP_NCLASS:
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ /* The original code caused an unsigned overflow in 64 bit systems,
+ so now we use a conditional statement. */
+ if (op == OP_XCLASS)
+ cc += GET(cc, 1);
+ else
+ cc += PRIV(OP_lengths)[OP_CLASS];
+#else
+ cc += PRIV(OP_lengths)[OP_CLASS];
+#endif
+
+ switch (*cc)
+ {
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ branchlength++;
+ /* Fall through */
+
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSQUERY:
+ cc++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ branchlength += GET2(cc,1);
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default:
+ branchlength++;
+ break;
+ }
+ break;
+
+ /* Backreferences and subroutine calls (OP_RECURSE) are treated in the same
+ way: we find the minimum length for the subpattern. A recursion
+ (backreference or subroutine) causes an a flag to be set that causes the
+ length of this branch to be ignored. The logic is that a recursion can only
+ make sense if there is another alternative that stops the recursing. That
+ will provide the minimum length (when no recursion happens).
+
+ If PCRE2_MATCH_UNSET_BACKREF is set, a backreference to an unset bracket
+ matches an empty string (by default it causes a matching failure), so in
+ that case we must set the minimum length to zero. */
+
+ /* Duplicate named pattern back reference. We cannot reliably find a length
+ for this if duplicate numbers are present in the pattern. */
+
+ case OP_DNREF:
+ case OP_DNREFI:
+ if (dupcapused) return -1;
+ if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0)
+ {
+ int count = GET2(cc, 1+IMM2_SIZE);
+ PCRE2_UCHAR *slot =
+ (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ GET2(cc, 1) * re->name_entry_size;
+
+ d = INT_MAX;
+
+ /* Scan all groups with the same name; find the shortest. */
+
+ while (count-- > 0)
+ {
+ int dd, i;
+ recno = GET2(slot, 0);
+
+ if (recno <= backref_cache[0] && backref_cache[recno] >= 0)
+ dd = backref_cache[recno];
+ else
+ {
+ ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno);
+ if (cs == NULL) return -2;
+ do ce += GET(ce, 1); while (*ce == OP_ALT);
+ if (cc > cs && cc < ce) /* Simple recursion */
+ {
+ dd = 0;
+ had_recurse = TRUE;
+ }
+ else
+ {
+ recurse_check *r = recurses;
+ for (r = recurses; r != NULL; r = r->prev)
+ if (r->group == cs) break;
+ if (r != NULL) /* Mutual recursion */
+ {
+ dd = 0;
+ had_recurse = TRUE;
+ }
+ else
+ {
+ this_recurse.prev = recurses;
+ this_recurse.group = cs;
+ dd = find_minlength(re, cs, startcode, utf, &this_recurse,
+ countptr, backref_cache);
+ if (dd < 0) return dd;
+ }
+ }
+
+ backref_cache[recno] = dd;
+ for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1;
+ backref_cache[0] = recno;
+ }
+
+ if (dd < d) d = dd;
+ if (d <= 0) break; /* No point looking at any more */
+ slot += re->name_entry_size;
+ }
+ }
+ else d = 0;
+ cc += 1 + 2*IMM2_SIZE;
+ goto REPEAT_BACK_REFERENCE;
+
+ /* Single back reference. We cannot find a length for this if duplicate
+ numbers are present in the pattern. */
+
+ case OP_REF:
+ case OP_REFI:
+ if (dupcapused) return -1;
+ recno = GET2(cc, 1);
+ if (recno <= backref_cache[0] && backref_cache[recno] >= 0)
+ d = backref_cache[recno];
+ else
+ {
+ int i;
+ if ((re->overall_options & PCRE2_MATCH_UNSET_BACKREF) == 0)
+ {
+ ce = cs = (PCRE2_UCHAR *)PRIV(find_bracket)(startcode, utf, recno);
+ if (cs == NULL) return -2;
+ do ce += GET(ce, 1); while (*ce == OP_ALT);
+ if (cc > cs && cc < ce) /* Simple recursion */
+ {
+ d = 0;
+ had_recurse = TRUE;
+ }
+ else
+ {
+ recurse_check *r = recurses;
+ for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
+ if (r != NULL) /* Mutual recursion */
+ {
+ d = 0;
+ had_recurse = TRUE;
+ }
+ else
+ {
+ this_recurse.prev = recurses;
+ this_recurse.group = cs;
+ d = find_minlength(re, cs, startcode, utf, &this_recurse, countptr,
+ backref_cache);
+ if (d < 0) return d;
+ }
+ }
+ }
+ else d = 0;
+
+ backref_cache[recno] = d;
+ for (i = backref_cache[0] + 1; i < recno; i++) backref_cache[i] = -1;
+ backref_cache[0] = recno;
+ }
+
+ cc += 1 + IMM2_SIZE;
+
+ /* Handle repeated back references */
+
+ REPEAT_BACK_REFERENCE:
+ switch (*cc)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSQUERY:
+ min = 0;
+ cc++;
+ break;
+
+ case OP_CRPLUS:
+ case OP_CRMINPLUS:
+ case OP_CRPOSPLUS:
+ min = 1;
+ cc++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ min = GET2(cc, 1);
+ cc += 1 + 2 * IMM2_SIZE;
+ break;
+
+ default:
+ min = 1;
+ break;
+ }
+
+ /* Take care not to overflow: (1) min and d are ints, so check that their
+ product is not greater than INT_MAX. (2) branchlength is limited to
+ UINT16_MAX (checked at the top of the loop). */
+
+ if ((d > 0 && (INT_MAX/d) < min) || UINT16_MAX - branchlength < min*d)
+ branchlength = UINT16_MAX;
+ else branchlength += min * d;
+ break;
+
+ /* Recursion always refers to the first occurrence of a subpattern with a
+ given number. Therefore, we can always make use of caching, even when the
+ pattern contains multiple subpatterns with the same number. */
+
+ case OP_RECURSE:
+ cs = ce = (PCRE2_UCHAR *)startcode + GET(cc, 1);
+ recno = GET2(cs, 1+LINK_SIZE);
+ if (recno == prev_recurse_recno)
+ {
+ branchlength += prev_recurse_d;
+ }
+ else
+ {
+ do ce += GET(ce, 1); while (*ce == OP_ALT);
+ if (cc > cs && cc < ce) /* Simple recursion */
+ had_recurse = TRUE;
+ else
+ {
+ recurse_check *r = recurses;
+ for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
+ if (r != NULL) /* Mutual recursion */
+ had_recurse = TRUE;
+ else
+ {
+ this_recurse.prev = recurses;
+ this_recurse.group = cs;
+ prev_recurse_d = find_minlength(re, cs, startcode, utf, &this_recurse,
+ countptr, backref_cache);
+ if (prev_recurse_d < 0) return prev_recurse_d;
+ prev_recurse_recno = recno;
+ branchlength += prev_recurse_d;
+ }
+ }
+ }
+ cc += 1 + LINK_SIZE + once_fudge;
+ once_fudge = 0;
+ break;
+
+ /* Anything else does not or need not match a character. We can get the
+ item's length from the table, but for those that can match zero occurrences
+ of a character, we must take special action for UTF-8 characters. As it
+ happens, the "NOT" versions of these opcodes are used at present only for
+ ASCII characters, so they could be omitted from this list. However, in
+ future that may change, so we include them here so as not to leave a
+ gotcha for a future maintainer. */
+
+ case OP_UPTO:
+ case OP_UPTOI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_MINUPTO:
+ case OP_MINUPTOI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_POSUPTO:
+ case OP_POSUPTOI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+
+ case OP_STAR:
+ case OP_STARI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_MINSTAR:
+ case OP_MINSTARI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_POSSTAR:
+ case OP_POSSTARI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+
+ case OP_QUERY:
+ case OP_QUERYI:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_MINQUERY:
+ case OP_MINQUERYI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_POSQUERY:
+ case OP_POSQUERYI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+
+ cc += PRIV(OP_lengths)[op];
+#ifdef SUPPORT_UNICODE
+ if (utf && HAS_EXTRALEN(cc[-1])) cc += GET_EXTRALEN(cc[-1]);
+#endif
+ break;
+
+ /* Skip these, but we need to add in the name length. */
+
+ case OP_MARK:
+ case OP_COMMIT_ARG:
+ case OP_PRUNE_ARG:
+ case OP_SKIP_ARG:
+ case OP_THEN_ARG:
+ cc += PRIV(OP_lengths)[op] + cc[1];
+ break;
+
+ /* The remaining opcodes are just skipped over. */
+
+ case OP_CLOSE:
+ case OP_COMMIT:
+ case OP_FAIL:
+ case OP_PRUNE:
+ case OP_SET_SOM:
+ case OP_SKIP:
+ case OP_THEN:
+ cc += PRIV(OP_lengths)[op];
+ break;
+
+ /* This should not occur: we list all opcodes explicitly so that when
+ new ones get added they are properly considered. */
+
+ default:
+ return -3;
+ }
+ }
+/* Control never gets here */
+}
+
+
+
+/*************************************************
+* Set a bit and maybe its alternate case *
+*************************************************/
+
+/* Given a character, set its first code unit's bit in the table, and also the
+corresponding bit for the other version of a letter if we are caseless.
+
+Arguments:
+ re points to the regex block
+ p points to the first code unit of the character
+ caseless TRUE if caseless
+ utf TRUE for UTF mode
+
+Returns: pointer after the character
+*/
+
+static PCRE2_SPTR
+set_table_bit(pcre2_real_code *re, PCRE2_SPTR p, BOOL caseless, BOOL utf)
+{
+uint32_t c = *p++; /* First code unit */
+(void)utf; /* Stop compiler warning when UTF not supported */
+
+/* In 16-bit and 32-bit modes, code units greater than 0xff set the bit for
+0xff. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+if (c > 0xff) SET_BIT(0xff); else
+#endif
+
+SET_BIT(c);
+
+/* In UTF-8 or UTF-16 mode, pick up the remaining code units in order to find
+the end of the character, even when caseless. */
+
+#ifdef SUPPORT_UNICODE
+if (utf)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ if (c >= 0xc0) GETUTF8INC(c, p);
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ if ((c & 0xfc00) == 0xd800) GETUTF16INC(c, p);
+#endif
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* If caseless, handle the other case of the character. */
+
+if (caseless)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ PCRE2_UCHAR buff[6];
+ c = UCD_OTHERCASE(c);
+ (void)PRIV(ord2utf)(c, buff);
+ SET_BIT(buff[0]);
+#else /* 16-bit or 32-bit mode */
+ c = UCD_OTHERCASE(c);
+ if (c > 0xff) SET_BIT(0xff); else SET_BIT(c);
+#endif
+ }
+ else
+#endif /* SUPPORT_UNICODE */
+
+ /* Not UTF */
+
+ if (MAX_255(c)) SET_BIT(re->tables[fcc_offset + c]);
+ }
+
+return p;
+}
+
+
+
+/*************************************************
+* Set bits for a positive character type *
+*************************************************/
+
+/* This function sets starting bits for a character type. In UTF-8 mode, we can
+only do a direct setting for bytes less than 128, as otherwise there can be
+confusion with bytes in the middle of UTF-8 characters. In a "traditional"
+environment, the tables will only recognize ASCII characters anyway, but in at
+least one Windows environment, some higher bytes bits were set in the tables.
+So we deal with that case by considering the UTF-8 encoding.
+
+Arguments:
+ re the regex block
+ cbit type the type of character wanted
+ table_limit 32 for non-UTF-8; 16 for UTF-8
+
+Returns: nothing
+*/
+
+static void
+set_type_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit)
+{
+uint32_t c;
+for (c = 0; c < table_limit; c++)
+ re->start_bitmap[c] |= re->tables[c+cbits_offset+cbit_type];
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (table_limit == 32) return;
+for (c = 128; c < 256; c++)
+ {
+ if ((re->tables[cbits_offset + c/8] & (1 << (c&7))) != 0)
+ {
+ PCRE2_UCHAR buff[6];
+ (void)PRIV(ord2utf)(c, buff);
+ SET_BIT(buff[0]);
+ }
+ }
+#endif /* UTF-8 */
+}
+
+
+/*************************************************
+* Set bits for a negative character type *
+*************************************************/
+
+/* This function sets starting bits for a negative character type such as \D.
+In UTF-8 mode, we can only do a direct setting for bytes less than 128, as
+otherwise there can be confusion with bytes in the middle of UTF-8 characters.
+Unlike in the positive case, where we can set appropriate starting bits for
+specific high-valued UTF-8 characters, in this case we have to set the bits for
+all high-valued characters. The lowest is 0xc2, but we overkill by starting at
+0xc0 (192) for simplicity.
+
+Arguments:
+ re the regex block
+ cbit type the type of character wanted
+ table_limit 32 for non-UTF-8; 16 for UTF-8
+
+Returns: nothing
+*/
+
+static void
+set_nottype_bits(pcre2_real_code *re, int cbit_type, unsigned int table_limit)
+{
+uint32_t c;
+for (c = 0; c < table_limit; c++)
+ re->start_bitmap[c] |= ~(re->tables[c+cbits_offset+cbit_type]);
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+if (table_limit != 32) for (c = 24; c < 32; c++) re->start_bitmap[c] = 0xff;
+#endif
+}
+
+
+
+/*************************************************
+* Create bitmap of starting bytes *
+*************************************************/
+
+/* This function scans a compiled unanchored expression recursively and
+attempts to build a bitmap of the set of possible starting code units whose
+values are less than 256. In 16-bit and 32-bit mode, values above 255 all cause
+the 255 bit to be set. When calling set[_not]_type_bits() in UTF-8 (sic) mode
+we pass a value of 16 rather than 32 as the final argument. (See comments in
+those functions for the reason.)
+
+The SSB_CONTINUE return is useful for parenthesized groups in patterns such as
+(a*)b where the group provides some optional starting code units but scanning
+must continue at the outer level to find at least one mandatory code unit. At
+the outermost level, this function fails unless the result is SSB_DONE.
+
+Arguments:
+ re points to the compiled regex block
+ code points to an expression
+ utf TRUE if in UTF mode
+
+Returns: SSB_FAIL => Failed to find any starting code units
+ SSB_DONE => Found mandatory starting code units
+ SSB_CONTINUE => Found optional starting code units
+ SSB_UNKNOWN => Hit an unrecognized opcode
+*/
+
+static int
+set_start_bits(pcre2_real_code *re, PCRE2_SPTR code, BOOL utf)
+{
+uint32_t c;
+int yield = SSB_DONE;
+
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+int table_limit = utf? 16:32;
+#else
+int table_limit = 32;
+#endif
+
+do
+ {
+ BOOL try_next = TRUE;
+ PCRE2_SPTR tcode = code + 1 + LINK_SIZE;
+
+ if (*code == OP_CBRA || *code == OP_SCBRA ||
+ *code == OP_CBRAPOS || *code == OP_SCBRAPOS) tcode += IMM2_SIZE;
+
+ while (try_next) /* Loop for items in this branch */
+ {
+ int rc;
+ uint8_t *classmap = NULL;
+
+ switch(*tcode)
+ {
+ /* If we reach something we don't understand, it means a new opcode has
+ been created that hasn't been added to this function. Hopefully this
+ problem will be discovered during testing. */
+
+ default:
+ return SSB_UNKNOWN;
+
+ /* Fail for a valid opcode that implies no starting bits. */
+
+ case OP_ACCEPT:
+ case OP_ASSERT_ACCEPT:
+ case OP_ALLANY:
+ case OP_ANY:
+ case OP_ANYBYTE:
+ case OP_CIRCM:
+ case OP_CLOSE:
+ case OP_COMMIT:
+ case OP_COMMIT_ARG:
+ case OP_COND:
+ case OP_CREF:
+ case OP_FALSE:
+ case OP_TRUE:
+ case OP_DNCREF:
+ case OP_DNREF:
+ case OP_DNREFI:
+ case OP_DNRREF:
+ case OP_DOLL:
+ case OP_DOLLM:
+ case OP_END:
+ case OP_EOD:
+ case OP_EODN:
+ case OP_EXTUNI:
+ case OP_FAIL:
+ case OP_MARK:
+ case OP_NOT:
+ case OP_NOTEXACT:
+ case OP_NOTEXACTI:
+ case OP_NOTI:
+ case OP_NOTMINPLUS:
+ case OP_NOTMINPLUSI:
+ case OP_NOTMINQUERY:
+ case OP_NOTMINQUERYI:
+ case OP_NOTMINSTAR:
+ case OP_NOTMINSTARI:
+ case OP_NOTMINUPTO:
+ case OP_NOTMINUPTOI:
+ case OP_NOTPLUS:
+ case OP_NOTPLUSI:
+ case OP_NOTPOSPLUS:
+ case OP_NOTPOSPLUSI:
+ case OP_NOTPOSQUERY:
+ case OP_NOTPOSQUERYI:
+ case OP_NOTPOSSTAR:
+ case OP_NOTPOSSTARI:
+ case OP_NOTPOSUPTO:
+ case OP_NOTPOSUPTOI:
+ case OP_NOTPROP:
+ case OP_NOTQUERY:
+ case OP_NOTQUERYI:
+ case OP_NOTSTAR:
+ case OP_NOTSTARI:
+ case OP_NOTUPTO:
+ case OP_NOTUPTOI:
+ case OP_NOT_HSPACE:
+ case OP_NOT_VSPACE:
+ case OP_PRUNE:
+ case OP_PRUNE_ARG:
+ case OP_RECURSE:
+ case OP_REF:
+ case OP_REFI:
+ case OP_REVERSE:
+ case OP_RREF:
+ case OP_SCOND:
+ case OP_SET_SOM:
+ case OP_SKIP:
+ case OP_SKIP_ARG:
+ case OP_SOD:
+ case OP_SOM:
+ case OP_THEN:
+ case OP_THEN_ARG:
+ return SSB_FAIL;
+
+ /* OP_CIRC happens only at the start of an anchored branch (multiline ^
+ uses OP_CIRCM). Skip over it. */
+
+ case OP_CIRC:
+ tcode += PRIV(OP_lengths)[OP_CIRC];
+ break;
+
+ /* A "real" property test implies no starting bits, but the fake property
+ PT_CLIST identifies a list of characters. These lists are short, as they
+ are used for characters with more than one "other case", so there is no
+ point in recognizing them for OP_NOTPROP. */
+
+ case OP_PROP:
+ if (tcode[1] != PT_CLIST) return SSB_FAIL;
+ {
+ const uint32_t *p = PRIV(ucd_caseless_sets) + tcode[2];
+ while ((c = *p++) < NOTACHAR)
+ {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (utf)
+ {
+ PCRE2_UCHAR buff[6];
+ (void)PRIV(ord2utf)(c, buff);
+ c = buff[0];
+ }
+#endif
+ if (c > 0xff) SET_BIT(0xff); else SET_BIT(c);
+ }
+ }
+ try_next = FALSE;
+ break;
+
+ /* We can ignore word boundary tests. */
+
+ case OP_WORD_BOUNDARY:
+ case OP_NOT_WORD_BOUNDARY:
+ tcode++;
+ break;
+
+ /* If we hit a bracket or a positive lookahead assertion, recurse to set
+ bits from within the subpattern. If it can't find anything, we have to
+ give up. If it finds some mandatory character(s), we are done for this
+ branch. Otherwise, carry on scanning after the subpattern. */
+
+ case OP_BRA:
+ case OP_SBRA:
+ case OP_CBRA:
+ case OP_SCBRA:
+ case OP_BRAPOS:
+ case OP_SBRAPOS:
+ case OP_CBRAPOS:
+ case OP_SCBRAPOS:
+ case OP_ONCE:
+ case OP_ASSERT:
+ rc = set_start_bits(re, tcode, utf);
+ if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc;
+ if (rc == SSB_DONE) try_next = FALSE; else
+ {
+ do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ }
+ break;
+
+ /* If we hit ALT or KET, it means we haven't found anything mandatory in
+ this branch, though we might have found something optional. For ALT, we
+ continue with the next alternative, but we have to arrange that the final
+ result from subpattern is SSB_CONTINUE rather than SSB_DONE. For KET,
+ return SSB_CONTINUE: if this is the top level, that indicates failure,
+ but after a nested subpattern, it causes scanning to continue. */
+
+ case OP_ALT:
+ yield = SSB_CONTINUE;
+ try_next = FALSE;
+ break;
+
+ case OP_KET:
+ case OP_KETRMAX:
+ case OP_KETRMIN:
+ case OP_KETRPOS:
+ return SSB_CONTINUE;
+
+ /* Skip over callout */
+
+ case OP_CALLOUT:
+ tcode += PRIV(OP_lengths)[OP_CALLOUT];
+ break;
+
+ case OP_CALLOUT_STR:
+ tcode += GET(tcode, 1 + 2*LINK_SIZE);
+ break;
+
+ /* Skip over lookbehind and negative lookahead assertions */
+
+ case OP_ASSERT_NOT:
+ case OP_ASSERTBACK:
+ case OP_ASSERTBACK_NOT:
+ do tcode += GET(tcode, 1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ break;
+
+ /* BRAZERO does the bracket, but carries on. */
+
+ case OP_BRAZERO:
+ case OP_BRAMINZERO:
+ case OP_BRAPOSZERO:
+ rc = set_start_bits(re, ++tcode, utf);
+ if (rc == SSB_FAIL || rc == SSB_UNKNOWN) return rc;
+ do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ break;
+
+ /* SKIPZERO skips the bracket. */
+
+ case OP_SKIPZERO:
+ tcode++;
+ do tcode += GET(tcode,1); while (*tcode == OP_ALT);
+ tcode += 1 + LINK_SIZE;
+ break;
+
+ /* Single-char * or ? sets the bit and tries the next item */
+
+ case OP_STAR:
+ case OP_MINSTAR:
+ case OP_POSSTAR:
+ case OP_QUERY:
+ case OP_MINQUERY:
+ case OP_POSQUERY:
+ tcode = set_table_bit(re, tcode + 1, FALSE, utf);
+ break;
+
+ case OP_STARI:
+ case OP_MINSTARI:
+ case OP_POSSTARI:
+ case OP_QUERYI:
+ case OP_MINQUERYI:
+ case OP_POSQUERYI:
+ tcode = set_table_bit(re, tcode + 1, TRUE, utf);
+ break;
+
+ /* Single-char upto sets the bit and tries the next */
+
+ case OP_UPTO:
+ case OP_MINUPTO:
+ case OP_POSUPTO:
+ tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, FALSE, utf);
+ break;
+
+ case OP_UPTOI:
+ case OP_MINUPTOI:
+ case OP_POSUPTOI:
+ tcode = set_table_bit(re, tcode + 1 + IMM2_SIZE, TRUE, utf);
+ break;
+
+ /* At least one single char sets the bit and stops */
+
+ case OP_EXACT:
+ tcode += IMM2_SIZE;
+ /* Fall through */
+ case OP_CHAR:
+ case OP_PLUS:
+ case OP_MINPLUS:
+ case OP_POSPLUS:
+ (void)set_table_bit(re, tcode + 1, FALSE, utf);
+ try_next = FALSE;
+ break;
+
+ case OP_EXACTI:
+ tcode += IMM2_SIZE;
+ /* Fall through */
+ case OP_CHARI:
+ case OP_PLUSI:
+ case OP_MINPLUSI:
+ case OP_POSPLUSI:
+ (void)set_table_bit(re, tcode + 1, TRUE, utf);
+ try_next = FALSE;
+ break;
+
+ /* Special spacing and line-terminating items. These recognize specific
+ lists of characters. The difference between VSPACE and ANYNL is that the
+ latter can match the two-character CRLF sequence, but that is not
+ relevant for finding the first character, so their code here is
+ identical. */
+
+ case OP_HSPACE:
+ SET_BIT(CHAR_HT);
+ SET_BIT(CHAR_SPACE);
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for 0xA0 and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(0xA0);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of horizontal space characters. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ SET_BIT(0xC2); /* For U+00A0 */
+ SET_BIT(0xE1); /* For U+1680, U+180E */
+ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */
+ SET_BIT(0xE3); /* For U+3000 */
+ }
+ else
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
+ the code is EBCDIC. */
+ {
+#ifndef EBCDIC
+ SET_BIT(0xA0);
+#endif /* Not EBCDIC */
+ }
+#endif /* 8-bit support */
+
+ try_next = FALSE;
+ break;
+
+ case OP_ANYNL:
+ case OP_VSPACE:
+ SET_BIT(CHAR_LF);
+ SET_BIT(CHAR_VT);
+ SET_BIT(CHAR_FF);
+ SET_BIT(CHAR_CR);
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for NEL and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(CHAR_NEL);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of vertical space characters. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ SET_BIT(0xC2); /* For U+0085 (NEL) */
+ SET_BIT(0xE2); /* For U+2028, U+2029 */
+ }
+ else
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */
+ {
+ SET_BIT(CHAR_NEL);
+ }
+#endif /* 8-bit support */
+
+ try_next = FALSE;
+ break;
+
+ /* Single character types set the bits and stop. Note that if PCRE2_UCP
+ is set, we do not see these opcodes because \d etc are converted to
+ properties. Therefore, these apply in the case when only characters less
+ than 256 are recognized to match the types. */
+
+ case OP_NOT_DIGIT:
+ set_nottype_bits(re, cbit_digit, table_limit);
+ try_next = FALSE;
+ break;
+
+ case OP_DIGIT:
+ set_type_bits(re, cbit_digit, table_limit);
+ try_next = FALSE;
+ break;
+
+ case OP_NOT_WHITESPACE:
+ set_nottype_bits(re, cbit_space, table_limit);
+ try_next = FALSE;
+ break;
+
+ case OP_WHITESPACE:
+ set_type_bits(re, cbit_space, table_limit);
+ try_next = FALSE;
+ break;
+
+ case OP_NOT_WORDCHAR:
+ set_nottype_bits(re, cbit_word, table_limit);
+ try_next = FALSE;
+ break;
+
+ case OP_WORDCHAR:
+ set_type_bits(re, cbit_word, table_limit);
+ try_next = FALSE;
+ break;
+
+ /* One or more character type fudges the pointer and restarts, knowing
+ it will hit a single character type and stop there. */
+
+ case OP_TYPEPLUS:
+ case OP_TYPEMINPLUS:
+ case OP_TYPEPOSPLUS:
+ tcode++;
+ break;
+
+ case OP_TYPEEXACT:
+ tcode += 1 + IMM2_SIZE;
+ break;
+
+ /* Zero or more repeats of character types set the bits and then
+ try again. */
+
+ case OP_TYPEUPTO:
+ case OP_TYPEMINUPTO:
+ case OP_TYPEPOSUPTO:
+ tcode += IMM2_SIZE; /* Fall through */
+
+ case OP_TYPESTAR:
+ case OP_TYPEMINSTAR:
+ case OP_TYPEPOSSTAR:
+ case OP_TYPEQUERY:
+ case OP_TYPEMINQUERY:
+ case OP_TYPEPOSQUERY:
+ switch(tcode[1])
+ {
+ default:
+ case OP_ANY:
+ case OP_ALLANY:
+ return SSB_FAIL;
+
+ case OP_HSPACE:
+ SET_BIT(CHAR_HT);
+ SET_BIT(CHAR_SPACE);
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for 0xA0 and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(0xA0);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of horizontal space characters. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ SET_BIT(0xC2); /* For U+00A0 */
+ SET_BIT(0xE1); /* For U+1680, U+180E */
+ SET_BIT(0xE2); /* For U+2000 - U+200A, U+202F, U+205F */
+ SET_BIT(0xE3); /* For U+3000 */
+ }
+ else
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for 0xA0, unless
+ the code is EBCDIC. */
+ {
+#ifndef EBCDIC
+ SET_BIT(0xA0);
+#endif /* Not EBCDIC */
+ }
+#endif /* 8-bit support */
+ break;
+
+ case OP_ANYNL:
+ case OP_VSPACE:
+ SET_BIT(CHAR_LF);
+ SET_BIT(CHAR_VT);
+ SET_BIT(CHAR_FF);
+ SET_BIT(CHAR_CR);
+
+ /* For the 16-bit and 32-bit libraries (which can never be EBCDIC), set
+ the bits for NEL and for code units >= 255, independently of UTF. */
+
+#if PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(CHAR_NEL);
+ SET_BIT(0xFF);
+#else
+ /* For the 8-bit library in UTF-8 mode, set the bits for the first code
+ units of vertical space characters. */
+
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ SET_BIT(0xC2); /* For U+0085 (NEL) */
+ SET_BIT(0xE2); /* For U+2028, U+2029 */
+ }
+ else
+#endif
+ /* For the 8-bit library not in UTF-8 mode, set the bit for NEL. */
+ {
+ SET_BIT(CHAR_NEL);
+ }
+#endif /* 8-bit support */
+ break;
+
+ case OP_NOT_DIGIT:
+ set_nottype_bits(re, cbit_digit, table_limit);
+ break;
+
+ case OP_DIGIT:
+ set_type_bits(re, cbit_digit, table_limit);
+ break;
+
+ case OP_NOT_WHITESPACE:
+ set_nottype_bits(re, cbit_space, table_limit);
+ break;
+
+ case OP_WHITESPACE:
+ set_type_bits(re, cbit_space, table_limit);
+ break;
+
+ case OP_NOT_WORDCHAR:
+ set_nottype_bits(re, cbit_word, table_limit);
+ break;
+
+ case OP_WORDCHAR:
+ set_type_bits(re, cbit_word, table_limit);
+ break;
+ }
+
+ tcode += 2;
+ break;
+
+ /* Extended class: if there are any property checks, or if this is a
+ negative XCLASS without a map, give up. If there are no property checks,
+ there must be wide characters on the XCLASS list, because otherwise an
+ XCLASS would not have been created. This means that code points >= 255
+ are always potential starters. */
+
+#ifdef SUPPORT_WIDE_CHARS
+ case OP_XCLASS:
+ if ((tcode[1 + LINK_SIZE] & XCL_HASPROP) != 0 ||
+ (tcode[1 + LINK_SIZE] & (XCL_MAP|XCL_NOT)) == XCL_NOT)
+ return SSB_FAIL;
+
+ /* We have a positive XCLASS or a negative one without a map. Set up the
+ map pointer if there is one, and fall through. */
+
+ classmap = ((tcode[1 + LINK_SIZE] & XCL_MAP) == 0)? NULL :
+ (uint8_t *)(tcode + 1 + LINK_SIZE + 1);
+#endif
+ /* It seems that the fall through comment must be outside the #ifdef if
+ it is to avoid the gcc compiler warning. */
+
+ /* Fall through */
+
+ /* Enter here for a negative non-XCLASS. In the 8-bit library, if we are
+ in UTF mode, any byte with a value >= 0xc4 is a potentially valid starter
+ because it starts a character with a value > 255. In 8-bit non-UTF mode,
+ there is no difference between CLASS and NCLASS. In all other wide
+ character modes, set the 0xFF bit to indicate code units >= 255. */
+
+ case OP_NCLASS:
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (utf)
+ {
+ re->start_bitmap[24] |= 0xf0; /* Bits for 0xc4 - 0xc8 */
+ memset(re->start_bitmap+25, 0xff, 7); /* Bits for 0xc9 - 0xff */
+ }
+#elif PCRE2_CODE_UNIT_WIDTH != 8
+ SET_BIT(0xFF); /* For characters >= 255 */
+#endif
+ /* Fall through */
+
+ /* Enter here for a positive non-XCLASS. If we have fallen through from
+ an XCLASS, classmap will already be set; just advance the code pointer.
+ Otherwise, set up classmap for a a non-XCLASS and advance past it. */
+
+ case OP_CLASS:
+ if (*tcode == OP_XCLASS) tcode += GET(tcode, 1); else
+ {
+ classmap = (uint8_t *)(++tcode);
+ tcode += 32 / sizeof(PCRE2_UCHAR);
+ }
+
+ /* When wide characters are supported, classmap may be NULL. In UTF-8
+ (sic) mode, the bits in a class bit map correspond to character values,
+ not to byte values. However, the bit map we are constructing is for byte
+ values. So we have to do a conversion for characters whose code point is
+ greater than 127. In fact, there are only two possible starting bytes for
+ characters in the range 128 - 255. */
+
+ if (classmap != NULL)
+ {
+#if defined SUPPORT_UNICODE && PCRE2_CODE_UNIT_WIDTH == 8
+ if (utf)
+ {
+ for (c = 0; c < 16; c++) re->start_bitmap[c] |= classmap[c];
+ for (c = 128; c < 256; c++)
+ {
+ if ((classmap[c/8] & (1 << (c&7))) != 0)
+ {
+ int d = (c >> 6) | 0xc0; /* Set bit for this starter */
+ re->start_bitmap[d/8] |= (1 << (d&7)); /* and then skip on to the */
+ c = (c & 0xc0) + 0x40 - 1; /* next relevant character. */
+ }
+ }
+ }
+ else
+#endif
+ /* In all modes except UTF-8, the two bit maps are compatible. */
+
+ {
+ for (c = 0; c < 32; c++) re->start_bitmap[c] |= classmap[c];
+ }
+ }
+
+ /* Act on what follows the class. For a zero minimum repeat, continue;
+ otherwise stop processing. */
+
+ switch (*tcode)
+ {
+ case OP_CRSTAR:
+ case OP_CRMINSTAR:
+ case OP_CRQUERY:
+ case OP_CRMINQUERY:
+ case OP_CRPOSSTAR:
+ case OP_CRPOSQUERY:
+ tcode++;
+ break;
+
+ case OP_CRRANGE:
+ case OP_CRMINRANGE:
+ case OP_CRPOSRANGE:
+ if (GET2(tcode, 1) == 0) tcode += 1 + 2 * IMM2_SIZE;
+ else try_next = FALSE;
+ break;
+
+ default:
+ try_next = FALSE;
+ break;
+ }
+ break; /* End of class handling case */
+ } /* End of switch for opcodes */
+ } /* End of try_next loop */
+
+ code += GET(code, 1); /* Advance to next branch */
+ }
+while (*code == OP_ALT);
+
+return yield;
+}
+
+
+
+/*************************************************
+* Study a compiled expression *
+*************************************************/
+
+/* This function is handed a compiled expression that it must study to produce
+information that will speed up the matching.
+
+Argument: points to the compiled expression
+Returns: 0 normally; non-zero should never normally occur
+ 1 unknown opcode in set_start_bits
+ 2 missing capturing bracket
+ 3 unknown opcode in find_minlength
+*/
+
+int
+PRIV(study)(pcre2_real_code *re)
+{
+int min;
+int count = 0;
+PCRE2_UCHAR *code;
+BOOL utf = (re->overall_options & PCRE2_UTF) != 0;
+
+/* Find start of compiled code */
+
+code = (PCRE2_UCHAR *)((uint8_t *)re + sizeof(pcre2_real_code)) +
+ re->name_entry_size * re->name_count;
+
+/* For a pattern that has a first code unit, or a multiline pattern that
+matches only at "line start", there is no point in seeking a list of starting
+code units. */
+
+if ((re->flags & (PCRE2_FIRSTSET|PCRE2_STARTLINE)) == 0)
+ {
+ int rc = set_start_bits(re, code, utf);
+ if (rc == SSB_UNKNOWN) return 1;
+ if (rc == SSB_DONE) re->flags |= PCRE2_FIRSTMAPSET;
+ }
+
+/* Find the minimum length of subject string. If the pattern can match an empty
+string, the minimum length is already known. If there are more back references
+than the size of the vector we are going to cache them in, do nothing. A
+pattern that complicated will probably take a long time to analyze and may in
+any case turn out to be too complicated. Note that back reference minima are
+held as 16-bit numbers. */
+
+if ((re->flags & PCRE2_MATCH_EMPTY) == 0 &&
+ re->top_backref <= MAX_CACHE_BACKREF)
+ {
+ int backref_cache[MAX_CACHE_BACKREF+1];
+ backref_cache[0] = 0; /* Highest one that is set */
+ min = find_minlength(re, code, code, utf, NULL, &count, backref_cache);
+ switch(min)
+ {
+ case -1: /* \C in UTF mode or (*ACCEPT) or over-complex regex */
+ break; /* Leave minlength unchanged (will be zero) */
+
+ case -2:
+ return 2; /* missing capturing bracket */
+
+ case -3:
+ return 3; /* unrecognized opcode */
+
+ default:
+ if (min > UINT16_MAX) min = UINT16_MAX;
+ re->minlength = min;
+ break;
+ }
+ }
+
+return 0;
+}
+
+/* End of pcre2_study.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_substitute.c b/test/monniaux/pcre2-10.32/pcre2_substitute.c
new file mode 100644
index 00000000..ab8d1090
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_substitute.c
@@ -0,0 +1,885 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#define PTR_STACK_SIZE 20
+
+#define SUBSTITUTE_OPTIONS \
+ (PCRE2_SUBSTITUTE_EXTENDED|PCRE2_SUBSTITUTE_GLOBAL| \
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH|PCRE2_SUBSTITUTE_UNKNOWN_UNSET| \
+ PCRE2_SUBSTITUTE_UNSET_EMPTY)
+
+
+
+/*************************************************
+* Find end of substitute text *
+*************************************************/
+
+/* In extended mode, we recognize ${name:+set text:unset text} and similar
+constructions. This requires the identification of unescaped : and }
+characters. This function scans for such. It must deal with nested ${
+constructions. The pointer to the text is updated, either to the required end
+character, or to where an error was detected.
+
+Arguments:
+ code points to the compiled expression (for options)
+ ptrptr points to the pointer to the start of the text (updated)
+ ptrend end of the whole string
+ last TRUE if the last expected string (only } recognized)
+
+Returns: 0 on success
+ negative error code on failure
+*/
+
+static int
+find_text_end(const pcre2_code *code, PCRE2_SPTR *ptrptr, PCRE2_SPTR ptrend,
+ BOOL last)
+{
+int rc = 0;
+uint32_t nestlevel = 0;
+BOOL literal = FALSE;
+PCRE2_SPTR ptr = *ptrptr;
+
+for (; ptr < ptrend; ptr++)
+ {
+ if (literal)
+ {
+ if (ptr[0] == CHAR_BACKSLASH && ptr < ptrend - 1 && ptr[1] == CHAR_E)
+ {
+ literal = FALSE;
+ ptr += 1;
+ }
+ }
+
+ else if (*ptr == CHAR_RIGHT_CURLY_BRACKET)
+ {
+ if (nestlevel == 0) goto EXIT;
+ nestlevel--;
+ }
+
+ else if (*ptr == CHAR_COLON && !last && nestlevel == 0) goto EXIT;
+
+ else if (*ptr == CHAR_DOLLAR_SIGN)
+ {
+ if (ptr < ptrend - 1 && ptr[1] == CHAR_LEFT_CURLY_BRACKET)
+ {
+ nestlevel++;
+ ptr += 1;
+ }
+ }
+
+ else if (*ptr == CHAR_BACKSLASH)
+ {
+ int erc;
+ int errorcode;
+ uint32_t ch;
+
+ if (ptr < ptrend - 1) switch (ptr[1])
+ {
+ case CHAR_L:
+ case CHAR_l:
+ case CHAR_U:
+ case CHAR_u:
+ ptr += 1;
+ continue;
+ }
+
+ ptr += 1; /* Must point after \ */
+ erc = PRIV(check_escape)(&ptr, ptrend, &ch, &errorcode,
+ code->overall_options, FALSE, NULL);
+ ptr -= 1; /* Back to last code unit of escape */
+ if (errorcode != 0)
+ {
+ rc = errorcode;
+ goto EXIT;
+ }
+
+ switch(erc)
+ {
+ case 0: /* Data character */
+ case ESC_E: /* Isolated \E is ignored */
+ break;
+
+ case ESC_Q:
+ literal = TRUE;
+ break;
+
+ default:
+ rc = PCRE2_ERROR_BADREPESCAPE;
+ goto EXIT;
+ }
+ }
+ }
+
+rc = PCRE2_ERROR_REPMISSINGBRACE; /* Terminator not found */
+
+EXIT:
+*ptrptr = ptr;
+return rc;
+}
+
+
+
+/*************************************************
+* Match and substitute *
+*************************************************/
+
+/* This function applies a compiled re to a subject string and creates a new
+string with substitutions. The first 7 arguments are the same as for
+pcre2_match(). Either string length may be PCRE2_ZERO_TERMINATED.
+
+Arguments:
+ code points to the compiled expression
+ subject points to the subject string
+ length length of subject string (may contain binary zeros)
+ start_offset where to start in the subject string
+ options option bits
+ match_data points to a match_data block, or is NULL
+ context points a PCRE2 context
+ replacement points to the replacement string
+ rlength length of replacement string
+ buffer where to put the substituted string
+ blength points to length of buffer; updated to length of string
+
+Returns: >= 0 number of substitutions made
+ < 0 an error code
+ PCRE2_ERROR_BADREPLACEMENT means invalid use of $
+*/
+
+/* This macro checks for space in the buffer before copying into it. On
+overflow, either give an error immediately, or keep on, accumulating the
+length. */
+
+#define CHECKMEMCPY(from,length) \
+ if (!overflowed && lengthleft < length) \
+ { \
+ if ((suboptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) == 0) goto NOROOM; \
+ overflowed = TRUE; \
+ extra_needed = length - lengthleft; \
+ } \
+ else if (overflowed) \
+ { \
+ extra_needed += length; \
+ } \
+ else \
+ { \
+ memcpy(buffer + buff_offset, from, CU2BYTES(length)); \
+ buff_offset += length; \
+ lengthleft -= length; \
+ }
+
+/* Here's the function */
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substitute(const pcre2_code *code, PCRE2_SPTR subject, PCRE2_SIZE length,
+ PCRE2_SIZE start_offset, uint32_t options, pcre2_match_data *match_data,
+ pcre2_match_context *mcontext, PCRE2_SPTR replacement, PCRE2_SIZE rlength,
+ PCRE2_UCHAR *buffer, PCRE2_SIZE *blength)
+{
+int rc;
+int subs;
+int forcecase = 0;
+int forcecasereset = 0;
+uint32_t ovector_count;
+uint32_t goptions = 0;
+uint32_t suboptions;
+BOOL match_data_created = FALSE;
+BOOL literal = FALSE;
+BOOL overflowed = FALSE;
+#ifdef SUPPORT_UNICODE
+BOOL utf = (code->overall_options & PCRE2_UTF) != 0;
+#endif
+PCRE2_UCHAR temp[6];
+PCRE2_SPTR ptr;
+PCRE2_SPTR repend;
+PCRE2_SIZE extra_needed = 0;
+PCRE2_SIZE buff_offset, buff_length, lengthleft, fraglength;
+PCRE2_SIZE *ovector;
+PCRE2_SIZE ovecsave[3];
+
+buff_offset = 0;
+lengthleft = buff_length = *blength;
+*blength = PCRE2_UNSET;
+ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET;
+
+/* Partial matching is not valid. */
+
+if ((options & (PCRE2_PARTIAL_HARD|PCRE2_PARTIAL_SOFT)) != 0)
+ return PCRE2_ERROR_BADOPTION;
+
+/* If no match data block is provided, create one. */
+
+if (match_data == NULL)
+ {
+ pcre2_general_context *gcontext = (mcontext == NULL)?
+ (pcre2_general_context *)code :
+ (pcre2_general_context *)mcontext;
+ match_data = pcre2_match_data_create_from_pattern(code, gcontext);
+ if (match_data == NULL) return PCRE2_ERROR_NOMEMORY;
+ match_data_created = TRUE;
+ }
+ovector = pcre2_get_ovector_pointer(match_data);
+ovector_count = pcre2_get_ovector_count(match_data);
+
+/* Find lengths of zero-terminated strings and the end of the replacement. */
+
+if (length == PCRE2_ZERO_TERMINATED) length = PRIV(strlen)(subject);
+if (rlength == PCRE2_ZERO_TERMINATED) rlength = PRIV(strlen)(replacement);
+repend = replacement + rlength;
+
+/* Check UTF replacement string if necessary. */
+
+#ifdef SUPPORT_UNICODE
+if (utf && (options & PCRE2_NO_UTF_CHECK) == 0)
+ {
+ rc = PRIV(valid_utf)(replacement, rlength, &(match_data->rightchar));
+ if (rc != 0)
+ {
+ match_data->leftchar = 0;
+ goto EXIT;
+ }
+ }
+#endif /* SUPPORT_UNICODE */
+
+/* Save the substitute options and remove them from the match options. */
+
+suboptions = options & SUBSTITUTE_OPTIONS;
+options &= ~SUBSTITUTE_OPTIONS;
+
+/* Copy up to the start offset */
+
+if (start_offset > length)
+ {
+ match_data->leftchar = 0;
+ rc = PCRE2_ERROR_BADOFFSET;
+ goto EXIT;
+ }
+CHECKMEMCPY(subject, start_offset);
+
+/* Loop for global substituting. */
+
+subs = 0;
+do
+ {
+ PCRE2_SPTR ptrstack[PTR_STACK_SIZE];
+ uint32_t ptrstackptr = 0;
+
+ rc = pcre2_match(code, subject, length, start_offset, options|goptions,
+ match_data, mcontext);
+
+#ifdef SUPPORT_UNICODE
+ if (utf) options |= PCRE2_NO_UTF_CHECK; /* Only need to check once */
+#endif
+
+ /* Any error other than no match returns the error code. No match when not
+ doing the special after-empty-match global rematch, or when at the end of the
+ subject, breaks the global loop. Otherwise, advance the starting point by one
+ character, copying it to the output, and try again. */
+
+ if (rc < 0)
+ {
+ PCRE2_SIZE save_start;
+
+ if (rc != PCRE2_ERROR_NOMATCH) goto EXIT;
+ if (goptions == 0 || start_offset >= length) break;
+
+ /* Advance by one code point. Then, if CRLF is a valid newline sequence and
+ we have advanced into the middle of it, advance one more code point. In
+ other words, do not start in the middle of CRLF, even if CR and LF on their
+ own are valid newlines. */
+
+ save_start = start_offset++;
+ if (subject[start_offset-1] == CHAR_CR &&
+ code->newline_convention != PCRE2_NEWLINE_CR &&
+ code->newline_convention != PCRE2_NEWLINE_LF &&
+ start_offset < length &&
+ subject[start_offset] == CHAR_LF)
+ start_offset++;
+
+ /* Otherwise, in UTF mode, advance past any secondary code points. */
+
+ else if ((code->overall_options & PCRE2_UTF) != 0)
+ {
+#if PCRE2_CODE_UNIT_WIDTH == 8
+ while (start_offset < length && (subject[start_offset] & 0xc0) == 0x80)
+ start_offset++;
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+ while (start_offset < length &&
+ (subject[start_offset] & 0xfc00) == 0xdc00)
+ start_offset++;
+#endif
+ }
+
+ /* Copy what we have advanced past, reset the special global options, and
+ continue to the next match. */
+
+ fraglength = start_offset - save_start;
+ CHECKMEMCPY(subject + save_start, fraglength);
+ goptions = 0;
+ continue;
+ }
+
+ /* Handle a successful match. Matches that use \K to end before they start
+ or start before the current point in the subject are not supported. */
+
+ if (ovector[1] < ovector[0] || ovector[0] < start_offset)
+ {
+ rc = PCRE2_ERROR_BADSUBSPATTERN;
+ goto EXIT;
+ }
+
+ /* Check for the same match as previous. This is legitimate after matching an
+ empty string that starts after the initial match offset. We have tried again
+ at the match point in case the pattern is one like /(?<=\G.)/ which can never
+ match at its starting point, so running the match achieves the bumpalong. If
+ we do get the same (null) match at the original match point, it isn't such a
+ pattern, so we now do the empty string magic. In all other cases, a repeat
+ match should never occur. */
+
+ if (ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1])
+ {
+ if (ovector[0] == ovector[1] && ovecsave[2] != start_offset)
+ {
+ goptions = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+ ovecsave[2] = start_offset;
+ continue; /* Back to the top of the loop */
+ }
+ rc = PCRE2_ERROR_INTERNAL_DUPMATCH;
+ goto EXIT;
+ }
+
+ /* Count substitutions with a paranoid check for integer overflow; surely no
+ real call to this function would ever hit this! */
+
+ if (subs == INT_MAX)
+ {
+ rc = PCRE2_ERROR_TOOMANYREPLACE;
+ goto EXIT;
+ }
+ subs++;
+
+ /* Copy the text leading up to the match. */
+
+ if (rc == 0) rc = ovector_count;
+ fraglength = ovector[0] - start_offset;
+ CHECKMEMCPY(subject + start_offset, fraglength);
+
+ /* Process the replacement string. Literal mode is set by \Q, but only in
+ extended mode when backslashes are being interpreted. In extended mode we
+ must handle nested substrings that are to be reprocessed. */
+
+ ptr = replacement;
+ for (;;)
+ {
+ uint32_t ch;
+ unsigned int chlen;
+
+ /* If at the end of a nested substring, pop the stack. */
+
+ if (ptr >= repend)
+ {
+ if (ptrstackptr <= 0) break; /* End of replacement string */
+ repend = ptrstack[--ptrstackptr];
+ ptr = ptrstack[--ptrstackptr];
+ continue;
+ }
+
+ /* Handle the next character */
+
+ if (literal)
+ {
+ if (ptr[0] == CHAR_BACKSLASH && ptr < repend - 1 && ptr[1] == CHAR_E)
+ {
+ literal = FALSE;
+ ptr += 2;
+ continue;
+ }
+ goto LOADLITERAL;
+ }
+
+ /* Not in literal mode. */
+
+ if (*ptr == CHAR_DOLLAR_SIGN)
+ {
+ int group, n;
+ uint32_t special = 0;
+ BOOL inparens;
+ BOOL star;
+ PCRE2_SIZE sublength;
+ PCRE2_SPTR text1_start = NULL;
+ PCRE2_SPTR text1_end = NULL;
+ PCRE2_SPTR text2_start = NULL;
+ PCRE2_SPTR text2_end = NULL;
+ PCRE2_UCHAR next;
+ PCRE2_UCHAR name[33];
+
+ if (++ptr >= repend) goto BAD;
+ if ((next = *ptr) == CHAR_DOLLAR_SIGN) goto LOADLITERAL;
+
+ group = -1;
+ n = 0;
+ inparens = FALSE;
+ star = FALSE;
+
+ if (next == CHAR_LEFT_CURLY_BRACKET)
+ {
+ if (++ptr >= repend) goto BAD;
+ next = *ptr;
+ inparens = TRUE;
+ }
+
+ if (next == CHAR_ASTERISK)
+ {
+ if (++ptr >= repend) goto BAD;
+ next = *ptr;
+ star = TRUE;
+ }
+
+ if (!star && next >= CHAR_0 && next <= CHAR_9)
+ {
+ group = next - CHAR_0;
+ while (++ptr < repend)
+ {
+ next = *ptr;
+ if (next < CHAR_0 || next > CHAR_9) break;
+ group = group * 10 + next - CHAR_0;
+
+ /* A check for a number greater than the hightest captured group
+ is sufficient here; no need for a separate overflow check. If unknown
+ groups are to be treated as unset, just skip over any remaining
+ digits and carry on. */
+
+ if (group > code->top_bracket)
+ {
+ if ((suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ while (++ptr < repend && *ptr >= CHAR_0 && *ptr <= CHAR_9);
+ break;
+ }
+ else
+ {
+ rc = PCRE2_ERROR_NOSUBSTRING;
+ goto PTREXIT;
+ }
+ }
+ }
+ }
+ else
+ {
+ const uint8_t *ctypes = code->tables + ctypes_offset;
+ while (MAX_255(next) && (ctypes[next] & ctype_word) != 0)
+ {
+ name[n++] = next;
+ if (n > 32) goto BAD;
+ if (++ptr >= repend) break;
+ next = *ptr;
+ }
+ if (n == 0) goto BAD;
+ name[n] = 0;
+ }
+
+ /* In extended mode we recognize ${name:+set text:unset text} and
+ ${name:-default text}. */
+
+ if (inparens)
+ {
+ if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+ !star && ptr < repend - 2 && next == CHAR_COLON)
+ {
+ special = *(++ptr);
+ if (special != CHAR_PLUS && special != CHAR_MINUS)
+ {
+ rc = PCRE2_ERROR_BADSUBSTITUTION;
+ goto PTREXIT;
+ }
+
+ text1_start = ++ptr;
+ rc = find_text_end(code, &ptr, repend, special == CHAR_MINUS);
+ if (rc != 0) goto PTREXIT;
+ text1_end = ptr;
+
+ if (special == CHAR_PLUS && *ptr == CHAR_COLON)
+ {
+ text2_start = ++ptr;
+ rc = find_text_end(code, &ptr, repend, TRUE);
+ if (rc != 0) goto PTREXIT;
+ text2_end = ptr;
+ }
+ }
+
+ else
+ {
+ if (ptr >= repend || *ptr != CHAR_RIGHT_CURLY_BRACKET)
+ {
+ rc = PCRE2_ERROR_REPMISSINGBRACE;
+ goto PTREXIT;
+ }
+ }
+
+ ptr++;
+ }
+
+ /* Have found a syntactically correct group number or name, or *name.
+ Only *MARK is currently recognized. */
+
+ if (star)
+ {
+ if (PRIV(strcmp_c8)(name, STRING_MARK) == 0)
+ {
+ PCRE2_SPTR mark = pcre2_get_mark(match_data);
+ if (mark != NULL)
+ {
+ PCRE2_SPTR mark_start = mark;
+ while (*mark != 0) mark++;
+ fraglength = mark - mark_start;
+ CHECKMEMCPY(mark_start, fraglength);
+ }
+ }
+ else goto BAD;
+ }
+
+ /* Substitute the contents of a group. We don't use substring_copy
+ functions any more, in order to support case forcing. */
+
+ else
+ {
+ PCRE2_SPTR subptr, subptrend;
+
+ /* Find a number for a named group. In case there are duplicate names,
+ search for the first one that is set. If the name is not found when
+ PCRE2_SUBSTITUTE_UNKNOWN_EMPTY is set, set the group number to a
+ non-existent group. */
+
+ if (group < 0)
+ {
+ PCRE2_SPTR first, last, entry;
+ rc = pcre2_substring_nametable_scan(code, name, &first, &last);
+ if (rc == PCRE2_ERROR_NOSUBSTRING &&
+ (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ group = code->top_bracket + 1;
+ }
+ else
+ {
+ if (rc < 0) goto PTREXIT;
+ for (entry = first; entry <= last; entry += rc)
+ {
+ uint32_t ng = GET2(entry, 0);
+ if (ng < ovector_count)
+ {
+ if (group < 0) group = ng; /* First in ovector */
+ if (ovector[ng*2] != PCRE2_UNSET)
+ {
+ group = ng; /* First that is set */
+ break;
+ }
+ }
+ }
+
+ /* If group is still negative, it means we did not find a group
+ that is in the ovector. Just set the first group. */
+
+ if (group < 0) group = GET2(first, 0);
+ }
+ }
+
+ /* We now have a group that is identified by number. Find the length of
+ the captured string. If a group in a non-special substitution is unset
+ when PCRE2_SUBSTITUTE_UNSET_EMPTY is set, substitute nothing. */
+
+ rc = pcre2_substring_length_bynumber(match_data, group, &sublength);
+ if (rc < 0)
+ {
+ if (rc == PCRE2_ERROR_NOSUBSTRING &&
+ (suboptions & PCRE2_SUBSTITUTE_UNKNOWN_UNSET) != 0)
+ {
+ rc = PCRE2_ERROR_UNSET;
+ }
+ if (rc != PCRE2_ERROR_UNSET) goto PTREXIT; /* Non-unset errors */
+ if (special == 0) /* Plain substitution */
+ {
+ if ((suboptions & PCRE2_SUBSTITUTE_UNSET_EMPTY) != 0) continue;
+ goto PTREXIT; /* Else error */
+ }
+ }
+
+ /* If special is '+' we have a 'set' and possibly an 'unset' text,
+ both of which are reprocessed when used. If special is '-' we have a
+ default text for when the group is unset; it must be reprocessed. */
+
+ if (special != 0)
+ {
+ if (special == CHAR_MINUS)
+ {
+ if (rc == 0) goto LITERAL_SUBSTITUTE;
+ text2_start = text1_start;
+ text2_end = text1_end;
+ }
+
+ if (ptrstackptr >= PTR_STACK_SIZE) goto BAD;
+ ptrstack[ptrstackptr++] = ptr;
+ ptrstack[ptrstackptr++] = repend;
+
+ if (rc == 0)
+ {
+ ptr = text1_start;
+ repend = text1_end;
+ }
+ else
+ {
+ ptr = text2_start;
+ repend = text2_end;
+ }
+ continue;
+ }
+
+ /* Otherwise we have a literal substitution of a group's contents. */
+
+ LITERAL_SUBSTITUTE:
+ subptr = subject + ovector[group*2];
+ subptrend = subject + ovector[group*2 + 1];
+
+ /* Substitute a literal string, possibly forcing alphabetic case. */
+
+ while (subptr < subptrend)
+ {
+ GETCHARINCTEST(ch, subptr);
+ if (forcecase != 0)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t type = UCD_CHARTYPE(ch);
+ if (PRIV(ucp_gentype)[type] == ucp_L &&
+ type != ((forcecase > 0)? ucp_Lu : ucp_Ll))
+ ch = UCD_OTHERCASE(ch);
+ }
+ else
+#endif
+ {
+ if (((code->tables + cbits_offset +
+ ((forcecase > 0)? cbit_upper:cbit_lower)
+ )[ch/8] & (1 << (ch%8))) == 0)
+ ch = (code->tables + fcc_offset)[ch];
+ }
+ forcecase = forcecasereset;
+ }
+
+#ifdef SUPPORT_UNICODE
+ if (utf) chlen = PRIV(ord2utf)(ch, temp); else
+#endif
+ {
+ temp[0] = ch;
+ chlen = 1;
+ }
+ CHECKMEMCPY(temp, chlen);
+ }
+ }
+ }
+
+ /* Handle an escape sequence in extended mode. We can use check_escape()
+ to process \Q, \E, \c, \o, \x and \ followed by non-alphanumerics, but
+ the case-forcing escapes are not supported in pcre2_compile() so must be
+ recognized here. */
+
+ else if ((suboptions & PCRE2_SUBSTITUTE_EXTENDED) != 0 &&
+ *ptr == CHAR_BACKSLASH)
+ {
+ int errorcode;
+
+ if (ptr < repend - 1) switch (ptr[1])
+ {
+ case CHAR_L:
+ forcecase = forcecasereset = -1;
+ ptr += 2;
+ continue;
+
+ case CHAR_l:
+ forcecase = -1;
+ forcecasereset = 0;
+ ptr += 2;
+ continue;
+
+ case CHAR_U:
+ forcecase = forcecasereset = 1;
+ ptr += 2;
+ continue;
+
+ case CHAR_u:
+ forcecase = 1;
+ forcecasereset = 0;
+ ptr += 2;
+ continue;
+
+ default:
+ break;
+ }
+
+ ptr++; /* Point after \ */
+ rc = PRIV(check_escape)(&ptr, repend, &ch, &errorcode,
+ code->overall_options, FALSE, NULL);
+ if (errorcode != 0) goto BADESCAPE;
+
+ switch(rc)
+ {
+ case ESC_E:
+ forcecase = forcecasereset = 0;
+ continue;
+
+ case ESC_Q:
+ literal = TRUE;
+ continue;
+
+ case 0: /* Data character */
+ goto LITERAL;
+
+ default:
+ goto BADESCAPE;
+ }
+ }
+
+ /* Handle a literal code unit */
+
+ else
+ {
+ LOADLITERAL:
+ GETCHARINCTEST(ch, ptr); /* Get character value, increment pointer */
+
+ LITERAL:
+ if (forcecase != 0)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ uint32_t type = UCD_CHARTYPE(ch);
+ if (PRIV(ucp_gentype)[type] == ucp_L &&
+ type != ((forcecase > 0)? ucp_Lu : ucp_Ll))
+ ch = UCD_OTHERCASE(ch);
+ }
+ else
+#endif
+ {
+ if (((code->tables + cbits_offset +
+ ((forcecase > 0)? cbit_upper:cbit_lower)
+ )[ch/8] & (1 << (ch%8))) == 0)
+ ch = (code->tables + fcc_offset)[ch];
+ }
+ forcecase = forcecasereset;
+ }
+
+#ifdef SUPPORT_UNICODE
+ if (utf) chlen = PRIV(ord2utf)(ch, temp); else
+#endif
+ {
+ temp[0] = ch;
+ chlen = 1;
+ }
+ CHECKMEMCPY(temp, chlen);
+ } /* End handling a literal code unit */
+ } /* End of loop for scanning the replacement. */
+
+ /* The replacement has been copied to the output. Save the details of this
+ match. See above for how this data is used. If we matched an empty string, do
+ the magic for global matches. Finally, update the start offset to point to
+ the rest of the subject string. */
+
+ ovecsave[0] = ovector[0];
+ ovecsave[1] = ovector[1];
+ ovecsave[2] = start_offset;
+
+ goptions = (ovector[0] != ovector[1] || ovector[0] > start_offset)? 0 :
+ PCRE2_ANCHORED|PCRE2_NOTEMPTY_ATSTART;
+ start_offset = ovector[1];
+ } while ((suboptions & PCRE2_SUBSTITUTE_GLOBAL) != 0); /* Repeat "do" loop */
+
+/* Copy the rest of the subject. */
+
+fraglength = length - start_offset;
+CHECKMEMCPY(subject + start_offset, fraglength);
+temp[0] = 0;
+CHECKMEMCPY(temp , 1);
+
+/* If overflowed is set it means the PCRE2_SUBSTITUTE_OVERFLOW_LENGTH is set,
+and matching has carried on after a full buffer, in order to compute the length
+needed. Otherwise, an overflow generates an immediate error return. */
+
+if (overflowed)
+ {
+ rc = PCRE2_ERROR_NOMEMORY;
+ *blength = buff_length + extra_needed;
+ }
+
+/* After a successful execution, return the number of substitutions and set the
+length of buffer used, excluding the trailing zero. */
+
+else
+ {
+ rc = subs;
+ *blength = buff_offset - 1;
+ }
+
+EXIT:
+if (match_data_created) pcre2_match_data_free(match_data);
+ else match_data->rc = rc;
+return rc;
+
+NOROOM:
+rc = PCRE2_ERROR_NOMEMORY;
+goto EXIT;
+
+BAD:
+rc = PCRE2_ERROR_BADREPLACEMENT;
+goto PTREXIT;
+
+BADESCAPE:
+rc = PCRE2_ERROR_BADREPESCAPE;
+
+PTREXIT:
+*blength = (PCRE2_SIZE)(ptr - replacement);
+goto EXIT;
+}
+
+/* End of pcre2_substitute.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_substring.c b/test/monniaux/pcre2-10.32/pcre2_substring.c
new file mode 100644
index 00000000..ddf5774e
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_substring.c
@@ -0,0 +1,547 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+
+
+/*************************************************
+* Copy named captured string to given buffer *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by name. If the regex permits duplicate names, the first
+substring that is set is chosen.
+
+Arguments:
+ match_data points to the match data
+ stringname the name of the required substring
+ buffer where to put the substring
+ sizeptr the size of the buffer, updated to the size of the substring
+
+Returns: if successful: zero
+ if not successful, a negative error code:
+ (1) an error from nametable_scan()
+ (2) an error from copy_bynumber()
+ (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector
+ (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_copy_byname(pcre2_match_data *match_data, PCRE2_SPTR stringname,
+ PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+ &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+ {
+ uint32_t n = GET2(entry, 0);
+ if (n < match_data->oveccount)
+ {
+ if (match_data->ovector[n*2] != PCRE2_UNSET)
+ return pcre2_substring_copy_bynumber(match_data, n, buffer, sizeptr);
+ failrc = PCRE2_ERROR_UNSET;
+ }
+ }
+return failrc;
+}
+
+
+
+/*************************************************
+* Copy numbered captured string to given buffer *
+*************************************************/
+
+/* This function copies a single captured substring into a given buffer,
+identifying it by number.
+
+Arguments:
+ match_data points to the match data
+ stringnumber the number of the required substring
+ buffer where to put the substring
+ sizeptr the size of the buffer, updated to the size of the substring
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOMEMORY: buffer too small
+ PCRE2_ERROR_NOSUBSTRING: no such substring
+ PCRE2_ERROR_UNAVAILABLE: ovector too small
+ PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_copy_bynumber(pcre2_match_data *match_data,
+ uint32_t stringnumber, PCRE2_UCHAR *buffer, PCRE2_SIZE *sizeptr)
+{
+int rc;
+PCRE2_SIZE size;
+rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+if (rc < 0) return rc;
+if (size + 1 > *sizeptr) return PCRE2_ERROR_NOMEMORY;
+memcpy(buffer, match_data->subject + match_data->ovector[stringnumber*2],
+ CU2BYTES(size));
+buffer[size] = 0;
+*sizeptr = size;
+return 0;
+}
+
+
+
+/*************************************************
+* Extract named captured string *
+*************************************************/
+
+/* This function copies a single captured substring, identified by name, into
+new memory. If the regex permits duplicate names, the first substring that is
+set is chosen.
+
+Arguments:
+ match_data pointer to match_data
+ stringname the name of the required substring
+ stringptr where to put the pointer to the new memory
+ sizeptr where to put the length of the substring
+
+Returns: if successful: zero
+ if not successful, a negative value:
+ (1) an error from nametable_scan()
+ (2) an error from get_bynumber()
+ (3) PCRE2_ERROR_UNAVAILABLE: no group is in ovector
+ (4) PCRE2_ERROR_UNSET: all named groups in ovector are unset
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_get_byname(pcre2_match_data *match_data,
+ PCRE2_SPTR stringname, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+ &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+ {
+ uint32_t n = GET2(entry, 0);
+ if (n < match_data->oveccount)
+ {
+ if (match_data->ovector[n*2] != PCRE2_UNSET)
+ return pcre2_substring_get_bynumber(match_data, n, stringptr, sizeptr);
+ failrc = PCRE2_ERROR_UNSET;
+ }
+ }
+return failrc;
+}
+
+
+
+/*************************************************
+* Extract captured string to new memory *
+*************************************************/
+
+/* This function copies a single captured substring into a piece of new
+memory.
+
+Arguments:
+ match_data points to match data
+ stringnumber the number of the required substring
+ stringptr where to put a pointer to the new memory
+ sizeptr where to put the size of the substring
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOMEMORY: failed to get memory
+ PCRE2_ERROR_NOSUBSTRING: no such substring
+ PCRE2_ERROR_UNAVAILABLE: ovector too small
+ PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_get_bynumber(pcre2_match_data *match_data,
+ uint32_t stringnumber, PCRE2_UCHAR **stringptr, PCRE2_SIZE *sizeptr)
+{
+int rc;
+PCRE2_SIZE size;
+PCRE2_UCHAR *yield;
+rc = pcre2_substring_length_bynumber(match_data, stringnumber, &size);
+if (rc < 0) return rc;
+yield = PRIV(memctl_malloc)(sizeof(pcre2_memctl) +
+ (size + 1)*PCRE2_CODE_UNIT_WIDTH, (pcre2_memctl *)match_data);
+if (yield == NULL) return PCRE2_ERROR_NOMEMORY;
+yield = (PCRE2_UCHAR *)(((char *)yield) + sizeof(pcre2_memctl));
+memcpy(yield, match_data->subject + match_data->ovector[stringnumber*2],
+ CU2BYTES(size));
+yield[size] = 0;
+*stringptr = yield;
+*sizeptr = size;
+return 0;
+}
+
+
+
+/*************************************************
+* Free memory obtained by get_substring *
+*************************************************/
+
+/*
+Argument: the result of a previous pcre2_substring_get_byxxx()
+Returns: nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_substring_free(PCRE2_UCHAR *string)
+{
+if (string != NULL)
+ {
+ pcre2_memctl *memctl = (pcre2_memctl *)((char *)string - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+
+
+/*************************************************
+* Get length of a named substring *
+*************************************************/
+
+/* This function returns the length of a named captured substring. If the regex
+permits duplicate names, the first substring that is set is chosen.
+
+Arguments:
+ match_data pointer to match data
+ stringname the name of the required substring
+ sizeptr where to put the length
+
+Returns: 0 if successful, else a negative error number
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_length_byname(pcre2_match_data *match_data,
+ PCRE2_SPTR stringname, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SPTR first, last, entry;
+int failrc, entrysize;
+if (match_data->matchedby == PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ return PCRE2_ERROR_DFA_UFUNC;
+entrysize = pcre2_substring_nametable_scan(match_data->code, stringname,
+ &first, &last);
+if (entrysize < 0) return entrysize;
+failrc = PCRE2_ERROR_UNAVAILABLE;
+for (entry = first; entry <= last; entry += entrysize)
+ {
+ uint32_t n = GET2(entry, 0);
+ if (n < match_data->oveccount)
+ {
+ if (match_data->ovector[n*2] != PCRE2_UNSET)
+ return pcre2_substring_length_bynumber(match_data, n, sizeptr);
+ failrc = PCRE2_ERROR_UNSET;
+ }
+ }
+return failrc;
+}
+
+
+
+/*************************************************
+* Get length of a numbered substring *
+*************************************************/
+
+/* This function returns the length of a captured substring. If the start is
+beyond the end (which can happen when \K is used in an assertion), it sets the
+length to zero.
+
+Arguments:
+ match_data pointer to match data
+ stringnumber the number of the required substring
+ sizeptr where to put the length, if not NULL
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOSUBSTRING: no such substring
+ PCRE2_ERROR_UNAVAILABLE: ovector is too small
+ PCRE2_ERROR_UNSET: substring is not set
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_length_bynumber(pcre2_match_data *match_data,
+ uint32_t stringnumber, PCRE2_SIZE *sizeptr)
+{
+PCRE2_SIZE left, right;
+int count = match_data->rc;
+if (count == PCRE2_ERROR_PARTIAL)
+ {
+ if (stringnumber > 0) return PCRE2_ERROR_PARTIAL;
+ count = 0;
+ }
+else if (count < 0) return count; /* Match failed */
+
+if (match_data->matchedby != PCRE2_MATCHEDBY_DFA_INTERPRETER)
+ {
+ if (stringnumber > match_data->code->top_bracket)
+ return PCRE2_ERROR_NOSUBSTRING;
+ if (stringnumber >= match_data->oveccount)
+ return PCRE2_ERROR_UNAVAILABLE;
+ if (match_data->ovector[stringnumber*2] == PCRE2_UNSET)
+ return PCRE2_ERROR_UNSET;
+ }
+else /* Matched using pcre2_dfa_match() */
+ {
+ if (stringnumber >= match_data->oveccount) return PCRE2_ERROR_UNAVAILABLE;
+ if (count != 0 && stringnumber >= (uint32_t)count) return PCRE2_ERROR_UNSET;
+ }
+
+left = match_data->ovector[stringnumber*2];
+right = match_data->ovector[stringnumber*2+1];
+if (sizeptr != NULL) *sizeptr = (left > right)? 0 : right - left;
+return 0;
+}
+
+
+
+/*************************************************
+* Extract all captured strings to new memory *
+*************************************************/
+
+/* This function gets one chunk of memory and builds a list of pointers and all
+the captured substrings in it. A NULL pointer is put on the end of the list.
+The substrings are zero-terminated, but also, if the final argument is
+non-NULL, a list of lengths is also returned. This allows binary data to be
+handled.
+
+Arguments:
+ match_data points to the match data
+ listptr set to point to the list of pointers
+ lengthsptr set to point to the list of lengths (may be NULL)
+
+Returns: if successful: 0
+ if not successful, a negative error code:
+ PCRE2_ERROR_NOMEMORY: failed to get memory,
+ or a match failure code
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_list_get(pcre2_match_data *match_data, PCRE2_UCHAR ***listptr,
+ PCRE2_SIZE **lengthsptr)
+{
+int i, count, count2;
+PCRE2_SIZE size;
+PCRE2_SIZE *lensp;
+pcre2_memctl *memp;
+PCRE2_UCHAR **listp;
+PCRE2_UCHAR *sp;
+PCRE2_SIZE *ovector;
+
+if ((count = match_data->rc) < 0) return count; /* Match failed */
+if (count == 0) count = match_data->oveccount; /* Ovector too small */
+
+count2 = 2*count;
+ovector = match_data->ovector;
+size = sizeof(pcre2_memctl) + sizeof(PCRE2_UCHAR *); /* For final NULL */
+if (lengthsptr != NULL) size += sizeof(PCRE2_SIZE) * count; /* For lengths */
+
+for (i = 0; i < count2; i += 2)
+ {
+ size += sizeof(PCRE2_UCHAR *) + CU2BYTES(1);
+ if (ovector[i+1] > ovector[i]) size += CU2BYTES(ovector[i+1] - ovector[i]);
+ }
+
+memp = PRIV(memctl_malloc)(size, (pcre2_memctl *)match_data);
+if (memp == NULL) return PCRE2_ERROR_NOMEMORY;
+
+*listptr = listp = (PCRE2_UCHAR **)((char *)memp + sizeof(pcre2_memctl));
+lensp = (PCRE2_SIZE *)((char *)listp + sizeof(PCRE2_UCHAR *) * (count + 1));
+
+if (lengthsptr == NULL)
+ {
+ sp = (PCRE2_UCHAR *)lensp;
+ lensp = NULL;
+ }
+else
+ {
+ *lengthsptr = lensp;
+ sp = (PCRE2_UCHAR *)((char *)lensp + sizeof(PCRE2_SIZE) * count);
+ }
+
+for (i = 0; i < count2; i += 2)
+ {
+ size = (ovector[i+1] > ovector[i])? (ovector[i+1] - ovector[i]) : 0;
+
+ /* Size == 0 includes the case when the capture is unset. Avoid adding
+ PCRE2_UNSET to match_data->subject because it overflows, even though with
+ zero size calling memcpy() is harmless. */
+
+ if (size != 0) memcpy(sp, match_data->subject + ovector[i], CU2BYTES(size));
+ *listp++ = sp;
+ if (lensp != NULL) *lensp++ = size;
+ sp += size;
+ *sp++ = 0;
+ }
+
+*listp = NULL;
+return 0;
+}
+
+
+
+/*************************************************
+* Free memory obtained by substring_list_get *
+*************************************************/
+
+/*
+Argument: the result of a previous pcre2_substring_list_get()
+Returns: nothing
+*/
+
+PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
+pcre2_substring_list_free(PCRE2_SPTR *list)
+{
+if (list != NULL)
+ {
+ pcre2_memctl *memctl = (pcre2_memctl *)((char *)list - sizeof(pcre2_memctl));
+ memctl->free(memctl, memctl->memory_data);
+ }
+}
+
+
+
+/*************************************************
+* Find (multiple) entries for named string *
+*************************************************/
+
+/* This function scans the nametable for a given name, using binary chop. It
+returns either two pointers to the entries in the table, or, if no pointers are
+given, the number of a unique group with the given name. If duplicate names are
+permitted, and the name is not unique, an error is generated.
+
+Arguments:
+ code the compiled regex
+ stringname the name whose entries required
+ firstptr where to put the pointer to the first entry
+ lastptr where to put the pointer to the last entry
+
+Returns: PCRE2_ERROR_NOSUBSTRING if the name is not found
+ otherwise, if firstptr and lastptr are NULL:
+ a group number for a unique substring
+ else PCRE2_ERROR_NOUNIQUESUBSTRING
+ otherwise:
+ the length of each entry, having set firstptr and lastptr
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_nametable_scan(const pcre2_code *code, PCRE2_SPTR stringname,
+ PCRE2_SPTR *firstptr, PCRE2_SPTR *lastptr)
+{
+uint16_t bot = 0;
+uint16_t top = code->name_count;
+uint16_t entrysize = code->name_entry_size;
+PCRE2_SPTR nametable = (PCRE2_SPTR)((char *)code + sizeof(pcre2_real_code));
+
+while (top > bot)
+ {
+ uint16_t mid = (top + bot) / 2;
+ PCRE2_SPTR entry = nametable + entrysize*mid;
+ int c = PRIV(strcmp)(stringname, entry + IMM2_SIZE);
+ if (c == 0)
+ {
+ PCRE2_SPTR first;
+ PCRE2_SPTR last;
+ PCRE2_SPTR lastentry;
+ lastentry = nametable + entrysize * (code->name_count - 1);
+ first = last = entry;
+ while (first > nametable)
+ {
+ if (PRIV(strcmp)(stringname, (first - entrysize + IMM2_SIZE)) != 0) break;
+ first -= entrysize;
+ }
+ while (last < lastentry)
+ {
+ if (PRIV(strcmp)(stringname, (last + entrysize + IMM2_SIZE)) != 0) break;
+ last += entrysize;
+ }
+ if (firstptr == NULL) return (first == last)?
+ (int)GET2(entry, 0) : PCRE2_ERROR_NOUNIQUESUBSTRING;
+ *firstptr = first;
+ *lastptr = last;
+ return entrysize;
+ }
+ if (c > 0) bot = mid + 1; else top = mid;
+ }
+
+return PCRE2_ERROR_NOSUBSTRING;
+}
+
+
+/*************************************************
+* Find number for named string *
+*************************************************/
+
+/* This function is a convenience wrapper for pcre2_substring_nametable_scan()
+when it is known that names are unique. If there are duplicate names, it is not
+defined which number is returned.
+
+Arguments:
+ code the compiled regex
+ stringname the name whose number is required
+
+Returns: the number of the named parenthesis, or a negative number
+ PCRE2_ERROR_NOSUBSTRING if not found
+ PCRE2_ERROR_NOUNIQUESUBSTRING if not unique
+*/
+
+PCRE2_EXP_DEFN int PCRE2_CALL_CONVENTION
+pcre2_substring_number_from_name(const pcre2_code *code,
+ PCRE2_SPTR stringname)
+{
+return pcre2_substring_nametable_scan(code, stringname, NULL, NULL);
+}
+
+/* End of pcre2_substring.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_tables.c b/test/monniaux/pcre2-10.32/pcre2_tables.c
new file mode 100644
index 00000000..83d6f9de
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_tables.c
@@ -0,0 +1,827 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains some fixed tables that are used by more than one of the
+PCRE2 code modules. The tables are also #included by the pcre2test program,
+which uses macros to change their names from _pcre2_xxx to xxxx, thereby
+avoiding name clashes with the library. In this case, PCRE2_PCRE2TEST is
+defined. */
+
+#ifndef PCRE2_PCRE2TEST /* We're compiling the library */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pcre2_internal.h"
+#endif /* PCRE2_PCRE2TEST */
+
+
+/* Table of sizes for the fixed-length opcodes. It's defined in a macro so that
+the definition is next to the definition of the opcodes in pcre2_internal.h.
+This is mode-dependent, so is skipped when this file is included by pcre2test. */
+
+#ifndef PCRE2_PCRE2TEST
+const uint8_t PRIV(OP_lengths)[] = { OP_LENGTHS };
+#endif
+
+/* Tables of horizontal and vertical whitespace characters, suitable for
+adding to classes. */
+
+const uint32_t PRIV(hspace_list)[] = { HSPACE_LIST };
+const uint32_t PRIV(vspace_list)[] = { VSPACE_LIST };
+
+/* These tables are the pairs of delimiters that are valid for callout string
+arguments. For each starting delimiter there must be a matching ending
+delimiter, which in fact is different only for bracket-like delimiters. */
+
+const uint32_t PRIV(callout_start_delims)[] = {
+ CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK,
+ CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
+ CHAR_DOLLAR_SIGN, CHAR_LEFT_CURLY_BRACKET, 0 };
+
+const uint32_t PRIV(callout_end_delims[]) = {
+ CHAR_GRAVE_ACCENT, CHAR_APOSTROPHE, CHAR_QUOTATION_MARK,
+ CHAR_CIRCUMFLEX_ACCENT, CHAR_PERCENT_SIGN, CHAR_NUMBER_SIGN,
+ CHAR_DOLLAR_SIGN, CHAR_RIGHT_CURLY_BRACKET, 0 };
+
+
+/*************************************************
+* Tables for UTF-8 support *
+*************************************************/
+
+/* These tables are required by pcre2test in 16- or 32-bit mode, as well
+as for the library in 8-bit mode, because pcre2test uses UTF-8 internally for
+handling wide characters. */
+
+#if defined PCRE2_PCRE2TEST || \
+ (defined SUPPORT_UNICODE && \
+ defined PCRE2_CODE_UNIT_WIDTH && \
+ PCRE2_CODE_UNIT_WIDTH == 8)
+
+/* These are the breakpoints for different numbers of bytes in a UTF-8
+character. */
+
+const int PRIV(utf8_table1)[] =
+ { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff};
+
+const int PRIV(utf8_table1_size) = sizeof(PRIV(utf8_table1)) / sizeof(int);
+
+/* These are the indicator bits and the mask for the data bits to set in the
+first byte of a character, indexed by the number of additional bytes. */
+
+const int PRIV(utf8_table2)[] = { 0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
+const int PRIV(utf8_table3)[] = { 0xff, 0x1f, 0x0f, 0x07, 0x03, 0x01};
+
+/* Table of the number of extra bytes, indexed by the first byte masked with
+0x3f. The highest number for a valid UTF-8 first byte is in fact 0x3d. */
+
+const uint8_t PRIV(utf8_table4)[] = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 };
+
+#endif /* UTF-8 support needed */
+
+
+#ifdef SUPPORT_UNICODE
+
+/* Table to translate from particular type value to the general value. */
+
+const uint32_t PRIV(ucp_gentype)[] = {
+ ucp_C, ucp_C, ucp_C, ucp_C, ucp_C, /* Cc, Cf, Cn, Co, Cs */
+ ucp_L, ucp_L, ucp_L, ucp_L, ucp_L, /* Ll, Lu, Lm, Lo, Lt */
+ ucp_M, ucp_M, ucp_M, /* Mc, Me, Mn */
+ ucp_N, ucp_N, ucp_N, /* Nd, Nl, No */
+ ucp_P, ucp_P, ucp_P, ucp_P, ucp_P, /* Pc, Pd, Pe, Pf, Pi */
+ ucp_P, ucp_P, /* Ps, Po */
+ ucp_S, ucp_S, ucp_S, ucp_S, /* Sc, Sk, Sm, So */
+ ucp_Z, ucp_Z, ucp_Z /* Zl, Zp, Zs */
+};
+
+/* This table encodes the rules for finding the end of an extended grapheme
+cluster. Every code point has a grapheme break property which is one of the
+ucp_gbXX values defined in pcre2_ucp.h. These changed between Unicode versions
+10 and 11. The 2-dimensional table is indexed by the properties of two adjacent
+code points. The left property selects a word from the table, and the right
+property selects a bit from that word like this:
+
+ PRIV(ucp_gbtable)[left-property] & (1 << right-property)
+
+The value is non-zero if a grapheme break is NOT permitted between the relevant
+two code points. The breaking rules are as follows:
+
+1. Break at the start and end of text (pretty obviously).
+
+2. Do not break between a CR and LF; otherwise, break before and after
+ controls.
+
+3. Do not break Hangul syllable sequences, the rules for which are:
+
+ L may be followed by L, V, LV or LVT
+ LV or V may be followed by V or T
+ LVT or T may be followed by T
+
+4. Do not break before extending characters or zero-width-joiner (ZWJ).
+
+The following rules are only for extended grapheme clusters (but that's what we
+are implementing).
+
+5. Do not break before SpacingMarks.
+
+6. Do not break after Prepend characters.
+
+7. Do not break within emoji modifier sequences or emoji zwj sequences. That
+ is, do not break between characters with the Extended_Pictographic property.
+ Extend and ZWJ characters are allowed between the characters; this cannot be
+ represented in this table, the code has to deal with it.
+
+8. Do not break within emoji flag sequences. That is, do not break between
+ regional indicator (RI) symbols if there are an odd number of RI characters
+ before the break point. This table encodes "join RI characters"; the code
+ has to deal with checking for previous adjoining RIs.
+
+9. Otherwise, break everywhere.
+*/
+
+#define ESZ (1<<ucp_gbExtend)|(1<<ucp_gbSpacingMark)|(1<<ucp_gbZWJ)
+
+const uint32_t PRIV(ucp_gbtable)[] = {
+ (1<<ucp_gbLF), /* 0 CR */
+ 0, /* 1 LF */
+ 0, /* 2 Control */
+ ESZ, /* 3 Extend */
+ ESZ|(1<<ucp_gbPrepend)| /* 4 Prepend */
+ (1<<ucp_gbL)|(1<<ucp_gbV)|(1<<ucp_gbT)|
+ (1<<ucp_gbLV)|(1<<ucp_gbLVT)|(1<<ucp_gbOther)|
+ (1<<ucp_gbRegionalIndicator),
+ ESZ, /* 5 SpacingMark */
+ ESZ|(1<<ucp_gbL)|(1<<ucp_gbV)|(1<<ucp_gbLV)| /* 6 L */
+ (1<<ucp_gbLVT),
+ ESZ|(1<<ucp_gbV)|(1<<ucp_gbT), /* 7 V */
+ ESZ|(1<<ucp_gbT), /* 8 T */
+ ESZ|(1<<ucp_gbV)|(1<<ucp_gbT), /* 9 LV */
+ ESZ|(1<<ucp_gbT), /* 10 LVT */
+ (1<<ucp_gbRegionalIndicator), /* 11 RegionalIndicator */
+ ESZ, /* 12 Other */
+ ESZ, /* 13 ZWJ */
+ ESZ|(1<<ucp_gbExtended_Pictographic) /* 14 Extended Pictographic */
+};
+
+#undef ESZ
+
+#ifdef SUPPORT_JIT
+/* This table reverses PRIV(ucp_gentype). We can save the cost
+of a memory load. */
+
+const int PRIV(ucp_typerange)[] = {
+ ucp_Cc, ucp_Cs,
+ ucp_Ll, ucp_Lu,
+ ucp_Mc, ucp_Mn,
+ ucp_Nd, ucp_No,
+ ucp_Pc, ucp_Ps,
+ ucp_Sc, ucp_So,
+ ucp_Zl, ucp_Zs,
+};
+#endif /* SUPPORT_JIT */
+
+/* The PRIV(utt)[] table below translates Unicode property names into type and
+code values. It is searched by binary chop, so must be in collating sequence of
+name. Originally, the table contained pointers to the name strings in the first
+field of each entry. However, that leads to a large number of relocations when
+a shared library is dynamically loaded. A significant reduction is made by
+putting all the names into a single, large string and then using offsets in the
+table itself. Maintenance is more error-prone, but frequent changes to this
+data are unlikely.
+
+July 2008: There is now a script called maint/GenerateUtt.py that can be used
+to generate this data automatically instead of maintaining it by hand.
+
+The script was updated in March 2009 to generate a new EBCDIC-compliant
+version. Like all other character and string literals that are compared against
+the regular expression pattern, we must use STR_ macros instead of literal
+strings to make sure that UTF-8 support works on EBCDIC platforms. */
+
+#define STRING_Adlam0 STR_A STR_d STR_l STR_a STR_m "\0"
+#define STRING_Ahom0 STR_A STR_h STR_o STR_m "\0"
+#define STRING_Anatolian_Hieroglyphs0 STR_A STR_n STR_a STR_t STR_o STR_l STR_i STR_a STR_n STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
+#define STRING_Any0 STR_A STR_n STR_y "\0"
+#define STRING_Arabic0 STR_A STR_r STR_a STR_b STR_i STR_c "\0"
+#define STRING_Armenian0 STR_A STR_r STR_m STR_e STR_n STR_i STR_a STR_n "\0"
+#define STRING_Avestan0 STR_A STR_v STR_e STR_s STR_t STR_a STR_n "\0"
+#define STRING_Balinese0 STR_B STR_a STR_l STR_i STR_n STR_e STR_s STR_e "\0"
+#define STRING_Bamum0 STR_B STR_a STR_m STR_u STR_m "\0"
+#define STRING_Bassa_Vah0 STR_B STR_a STR_s STR_s STR_a STR_UNDERSCORE STR_V STR_a STR_h "\0"
+#define STRING_Batak0 STR_B STR_a STR_t STR_a STR_k "\0"
+#define STRING_Bengali0 STR_B STR_e STR_n STR_g STR_a STR_l STR_i "\0"
+#define STRING_Bhaiksuki0 STR_B STR_h STR_a STR_i STR_k STR_s STR_u STR_k STR_i "\0"
+#define STRING_Bopomofo0 STR_B STR_o STR_p STR_o STR_m STR_o STR_f STR_o "\0"
+#define STRING_Brahmi0 STR_B STR_r STR_a STR_h STR_m STR_i "\0"
+#define STRING_Braille0 STR_B STR_r STR_a STR_i STR_l STR_l STR_e "\0"
+#define STRING_Buginese0 STR_B STR_u STR_g STR_i STR_n STR_e STR_s STR_e "\0"
+#define STRING_Buhid0 STR_B STR_u STR_h STR_i STR_d "\0"
+#define STRING_C0 STR_C "\0"
+#define STRING_Canadian_Aboriginal0 STR_C STR_a STR_n STR_a STR_d STR_i STR_a STR_n STR_UNDERSCORE STR_A STR_b STR_o STR_r STR_i STR_g STR_i STR_n STR_a STR_l "\0"
+#define STRING_Carian0 STR_C STR_a STR_r STR_i STR_a STR_n "\0"
+#define STRING_Caucasian_Albanian0 STR_C STR_a STR_u STR_c STR_a STR_s STR_i STR_a STR_n STR_UNDERSCORE STR_A STR_l STR_b STR_a STR_n STR_i STR_a STR_n "\0"
+#define STRING_Cc0 STR_C STR_c "\0"
+#define STRING_Cf0 STR_C STR_f "\0"
+#define STRING_Chakma0 STR_C STR_h STR_a STR_k STR_m STR_a "\0"
+#define STRING_Cham0 STR_C STR_h STR_a STR_m "\0"
+#define STRING_Cherokee0 STR_C STR_h STR_e STR_r STR_o STR_k STR_e STR_e "\0"
+#define STRING_Cn0 STR_C STR_n "\0"
+#define STRING_Co0 STR_C STR_o "\0"
+#define STRING_Common0 STR_C STR_o STR_m STR_m STR_o STR_n "\0"
+#define STRING_Coptic0 STR_C STR_o STR_p STR_t STR_i STR_c "\0"
+#define STRING_Cs0 STR_C STR_s "\0"
+#define STRING_Cuneiform0 STR_C STR_u STR_n STR_e STR_i STR_f STR_o STR_r STR_m "\0"
+#define STRING_Cypriot0 STR_C STR_y STR_p STR_r STR_i STR_o STR_t "\0"
+#define STRING_Cyrillic0 STR_C STR_y STR_r STR_i STR_l STR_l STR_i STR_c "\0"
+#define STRING_Deseret0 STR_D STR_e STR_s STR_e STR_r STR_e STR_t "\0"
+#define STRING_Devanagari0 STR_D STR_e STR_v STR_a STR_n STR_a STR_g STR_a STR_r STR_i "\0"
+#define STRING_Dogra0 STR_D STR_o STR_g STR_r STR_a "\0"
+#define STRING_Duployan0 STR_D STR_u STR_p STR_l STR_o STR_y STR_a STR_n "\0"
+#define STRING_Egyptian_Hieroglyphs0 STR_E STR_g STR_y STR_p STR_t STR_i STR_a STR_n STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
+#define STRING_Elbasan0 STR_E STR_l STR_b STR_a STR_s STR_a STR_n "\0"
+#define STRING_Ethiopic0 STR_E STR_t STR_h STR_i STR_o STR_p STR_i STR_c "\0"
+#define STRING_Georgian0 STR_G STR_e STR_o STR_r STR_g STR_i STR_a STR_n "\0"
+#define STRING_Glagolitic0 STR_G STR_l STR_a STR_g STR_o STR_l STR_i STR_t STR_i STR_c "\0"
+#define STRING_Gothic0 STR_G STR_o STR_t STR_h STR_i STR_c "\0"
+#define STRING_Grantha0 STR_G STR_r STR_a STR_n STR_t STR_h STR_a "\0"
+#define STRING_Greek0 STR_G STR_r STR_e STR_e STR_k "\0"
+#define STRING_Gujarati0 STR_G STR_u STR_j STR_a STR_r STR_a STR_t STR_i "\0"
+#define STRING_Gunjala_Gondi0 STR_G STR_u STR_n STR_j STR_a STR_l STR_a STR_UNDERSCORE STR_G STR_o STR_n STR_d STR_i "\0"
+#define STRING_Gurmukhi0 STR_G STR_u STR_r STR_m STR_u STR_k STR_h STR_i "\0"
+#define STRING_Han0 STR_H STR_a STR_n "\0"
+#define STRING_Hangul0 STR_H STR_a STR_n STR_g STR_u STR_l "\0"
+#define STRING_Hanifi_Rohingya0 STR_H STR_a STR_n STR_i STR_f STR_i STR_UNDERSCORE STR_R STR_o STR_h STR_i STR_n STR_g STR_y STR_a "\0"
+#define STRING_Hanunoo0 STR_H STR_a STR_n STR_u STR_n STR_o STR_o "\0"
+#define STRING_Hatran0 STR_H STR_a STR_t STR_r STR_a STR_n "\0"
+#define STRING_Hebrew0 STR_H STR_e STR_b STR_r STR_e STR_w "\0"
+#define STRING_Hiragana0 STR_H STR_i STR_r STR_a STR_g STR_a STR_n STR_a "\0"
+#define STRING_Imperial_Aramaic0 STR_I STR_m STR_p STR_e STR_r STR_i STR_a STR_l STR_UNDERSCORE STR_A STR_r STR_a STR_m STR_a STR_i STR_c "\0"
+#define STRING_Inherited0 STR_I STR_n STR_h STR_e STR_r STR_i STR_t STR_e STR_d "\0"
+#define STRING_Inscriptional_Pahlavi0 STR_I STR_n STR_s STR_c STR_r STR_i STR_p STR_t STR_i STR_o STR_n STR_a STR_l STR_UNDERSCORE STR_P STR_a STR_h STR_l STR_a STR_v STR_i "\0"
+#define STRING_Inscriptional_Parthian0 STR_I STR_n STR_s STR_c STR_r STR_i STR_p STR_t STR_i STR_o STR_n STR_a STR_l STR_UNDERSCORE STR_P STR_a STR_r STR_t STR_h STR_i STR_a STR_n "\0"
+#define STRING_Javanese0 STR_J STR_a STR_v STR_a STR_n STR_e STR_s STR_e "\0"
+#define STRING_Kaithi0 STR_K STR_a STR_i STR_t STR_h STR_i "\0"
+#define STRING_Kannada0 STR_K STR_a STR_n STR_n STR_a STR_d STR_a "\0"
+#define STRING_Katakana0 STR_K STR_a STR_t STR_a STR_k STR_a STR_n STR_a "\0"
+#define STRING_Kayah_Li0 STR_K STR_a STR_y STR_a STR_h STR_UNDERSCORE STR_L STR_i "\0"
+#define STRING_Kharoshthi0 STR_K STR_h STR_a STR_r STR_o STR_s STR_h STR_t STR_h STR_i "\0"
+#define STRING_Khmer0 STR_K STR_h STR_m STR_e STR_r "\0"
+#define STRING_Khojki0 STR_K STR_h STR_o STR_j STR_k STR_i "\0"
+#define STRING_Khudawadi0 STR_K STR_h STR_u STR_d STR_a STR_w STR_a STR_d STR_i "\0"
+#define STRING_L0 STR_L "\0"
+#define STRING_L_AMPERSAND0 STR_L STR_AMPERSAND "\0"
+#define STRING_Lao0 STR_L STR_a STR_o "\0"
+#define STRING_Latin0 STR_L STR_a STR_t STR_i STR_n "\0"
+#define STRING_Lepcha0 STR_L STR_e STR_p STR_c STR_h STR_a "\0"
+#define STRING_Limbu0 STR_L STR_i STR_m STR_b STR_u "\0"
+#define STRING_Linear_A0 STR_L STR_i STR_n STR_e STR_a STR_r STR_UNDERSCORE STR_A "\0"
+#define STRING_Linear_B0 STR_L STR_i STR_n STR_e STR_a STR_r STR_UNDERSCORE STR_B "\0"
+#define STRING_Lisu0 STR_L STR_i STR_s STR_u "\0"
+#define STRING_Ll0 STR_L STR_l "\0"
+#define STRING_Lm0 STR_L STR_m "\0"
+#define STRING_Lo0 STR_L STR_o "\0"
+#define STRING_Lt0 STR_L STR_t "\0"
+#define STRING_Lu0 STR_L STR_u "\0"
+#define STRING_Lycian0 STR_L STR_y STR_c STR_i STR_a STR_n "\0"
+#define STRING_Lydian0 STR_L STR_y STR_d STR_i STR_a STR_n "\0"
+#define STRING_M0 STR_M "\0"
+#define STRING_Mahajani0 STR_M STR_a STR_h STR_a STR_j STR_a STR_n STR_i "\0"
+#define STRING_Makasar0 STR_M STR_a STR_k STR_a STR_s STR_a STR_r "\0"
+#define STRING_Malayalam0 STR_M STR_a STR_l STR_a STR_y STR_a STR_l STR_a STR_m "\0"
+#define STRING_Mandaic0 STR_M STR_a STR_n STR_d STR_a STR_i STR_c "\0"
+#define STRING_Manichaean0 STR_M STR_a STR_n STR_i STR_c STR_h STR_a STR_e STR_a STR_n "\0"
+#define STRING_Marchen0 STR_M STR_a STR_r STR_c STR_h STR_e STR_n "\0"
+#define STRING_Masaram_Gondi0 STR_M STR_a STR_s STR_a STR_r STR_a STR_m STR_UNDERSCORE STR_G STR_o STR_n STR_d STR_i "\0"
+#define STRING_Mc0 STR_M STR_c "\0"
+#define STRING_Me0 STR_M STR_e "\0"
+#define STRING_Medefaidrin0 STR_M STR_e STR_d STR_e STR_f STR_a STR_i STR_d STR_r STR_i STR_n "\0"
+#define STRING_Meetei_Mayek0 STR_M STR_e STR_e STR_t STR_e STR_i STR_UNDERSCORE STR_M STR_a STR_y STR_e STR_k "\0"
+#define STRING_Mende_Kikakui0 STR_M STR_e STR_n STR_d STR_e STR_UNDERSCORE STR_K STR_i STR_k STR_a STR_k STR_u STR_i "\0"
+#define STRING_Meroitic_Cursive0 STR_M STR_e STR_r STR_o STR_i STR_t STR_i STR_c STR_UNDERSCORE STR_C STR_u STR_r STR_s STR_i STR_v STR_e "\0"
+#define STRING_Meroitic_Hieroglyphs0 STR_M STR_e STR_r STR_o STR_i STR_t STR_i STR_c STR_UNDERSCORE STR_H STR_i STR_e STR_r STR_o STR_g STR_l STR_y STR_p STR_h STR_s "\0"
+#define STRING_Miao0 STR_M STR_i STR_a STR_o "\0"
+#define STRING_Mn0 STR_M STR_n "\0"
+#define STRING_Modi0 STR_M STR_o STR_d STR_i "\0"
+#define STRING_Mongolian0 STR_M STR_o STR_n STR_g STR_o STR_l STR_i STR_a STR_n "\0"
+#define STRING_Mro0 STR_M STR_r STR_o "\0"
+#define STRING_Multani0 STR_M STR_u STR_l STR_t STR_a STR_n STR_i "\0"
+#define STRING_Myanmar0 STR_M STR_y STR_a STR_n STR_m STR_a STR_r "\0"
+#define STRING_N0 STR_N "\0"
+#define STRING_Nabataean0 STR_N STR_a STR_b STR_a STR_t STR_a STR_e STR_a STR_n "\0"
+#define STRING_Nd0 STR_N STR_d "\0"
+#define STRING_New_Tai_Lue0 STR_N STR_e STR_w STR_UNDERSCORE STR_T STR_a STR_i STR_UNDERSCORE STR_L STR_u STR_e "\0"
+#define STRING_Newa0 STR_N STR_e STR_w STR_a "\0"
+#define STRING_Nko0 STR_N STR_k STR_o "\0"
+#define STRING_Nl0 STR_N STR_l "\0"
+#define STRING_No0 STR_N STR_o "\0"
+#define STRING_Nushu0 STR_N STR_u STR_s STR_h STR_u "\0"
+#define STRING_Ogham0 STR_O STR_g STR_h STR_a STR_m "\0"
+#define STRING_Ol_Chiki0 STR_O STR_l STR_UNDERSCORE STR_C STR_h STR_i STR_k STR_i "\0"
+#define STRING_Old_Hungarian0 STR_O STR_l STR_d STR_UNDERSCORE STR_H STR_u STR_n STR_g STR_a STR_r STR_i STR_a STR_n "\0"
+#define STRING_Old_Italic0 STR_O STR_l STR_d STR_UNDERSCORE STR_I STR_t STR_a STR_l STR_i STR_c "\0"
+#define STRING_Old_North_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_N STR_o STR_r STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
+#define STRING_Old_Permic0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_m STR_i STR_c "\0"
+#define STRING_Old_Persian0 STR_O STR_l STR_d STR_UNDERSCORE STR_P STR_e STR_r STR_s STR_i STR_a STR_n "\0"
+#define STRING_Old_Sogdian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0"
+#define STRING_Old_South_Arabian0 STR_O STR_l STR_d STR_UNDERSCORE STR_S STR_o STR_u STR_t STR_h STR_UNDERSCORE STR_A STR_r STR_a STR_b STR_i STR_a STR_n "\0"
+#define STRING_Old_Turkic0 STR_O STR_l STR_d STR_UNDERSCORE STR_T STR_u STR_r STR_k STR_i STR_c "\0"
+#define STRING_Oriya0 STR_O STR_r STR_i STR_y STR_a "\0"
+#define STRING_Osage0 STR_O STR_s STR_a STR_g STR_e "\0"
+#define STRING_Osmanya0 STR_O STR_s STR_m STR_a STR_n STR_y STR_a "\0"
+#define STRING_P0 STR_P "\0"
+#define STRING_Pahawh_Hmong0 STR_P STR_a STR_h STR_a STR_w STR_h STR_UNDERSCORE STR_H STR_m STR_o STR_n STR_g "\0"
+#define STRING_Palmyrene0 STR_P STR_a STR_l STR_m STR_y STR_r STR_e STR_n STR_e "\0"
+#define STRING_Pau_Cin_Hau0 STR_P STR_a STR_u STR_UNDERSCORE STR_C STR_i STR_n STR_UNDERSCORE STR_H STR_a STR_u "\0"
+#define STRING_Pc0 STR_P STR_c "\0"
+#define STRING_Pd0 STR_P STR_d "\0"
+#define STRING_Pe0 STR_P STR_e "\0"
+#define STRING_Pf0 STR_P STR_f "\0"
+#define STRING_Phags_Pa0 STR_P STR_h STR_a STR_g STR_s STR_UNDERSCORE STR_P STR_a "\0"
+#define STRING_Phoenician0 STR_P STR_h STR_o STR_e STR_n STR_i STR_c STR_i STR_a STR_n "\0"
+#define STRING_Pi0 STR_P STR_i "\0"
+#define STRING_Po0 STR_P STR_o "\0"
+#define STRING_Ps0 STR_P STR_s "\0"
+#define STRING_Psalter_Pahlavi0 STR_P STR_s STR_a STR_l STR_t STR_e STR_r STR_UNDERSCORE STR_P STR_a STR_h STR_l STR_a STR_v STR_i "\0"
+#define STRING_Rejang0 STR_R STR_e STR_j STR_a STR_n STR_g "\0"
+#define STRING_Runic0 STR_R STR_u STR_n STR_i STR_c "\0"
+#define STRING_S0 STR_S "\0"
+#define STRING_Samaritan0 STR_S STR_a STR_m STR_a STR_r STR_i STR_t STR_a STR_n "\0"
+#define STRING_Saurashtra0 STR_S STR_a STR_u STR_r STR_a STR_s STR_h STR_t STR_r STR_a "\0"
+#define STRING_Sc0 STR_S STR_c "\0"
+#define STRING_Sharada0 STR_S STR_h STR_a STR_r STR_a STR_d STR_a "\0"
+#define STRING_Shavian0 STR_S STR_h STR_a STR_v STR_i STR_a STR_n "\0"
+#define STRING_Siddham0 STR_S STR_i STR_d STR_d STR_h STR_a STR_m "\0"
+#define STRING_SignWriting0 STR_S STR_i STR_g STR_n STR_W STR_r STR_i STR_t STR_i STR_n STR_g "\0"
+#define STRING_Sinhala0 STR_S STR_i STR_n STR_h STR_a STR_l STR_a "\0"
+#define STRING_Sk0 STR_S STR_k "\0"
+#define STRING_Sm0 STR_S STR_m "\0"
+#define STRING_So0 STR_S STR_o "\0"
+#define STRING_Sogdian0 STR_S STR_o STR_g STR_d STR_i STR_a STR_n "\0"
+#define STRING_Sora_Sompeng0 STR_S STR_o STR_r STR_a STR_UNDERSCORE STR_S STR_o STR_m STR_p STR_e STR_n STR_g "\0"
+#define STRING_Soyombo0 STR_S STR_o STR_y STR_o STR_m STR_b STR_o "\0"
+#define STRING_Sundanese0 STR_S STR_u STR_n STR_d STR_a STR_n STR_e STR_s STR_e "\0"
+#define STRING_Syloti_Nagri0 STR_S STR_y STR_l STR_o STR_t STR_i STR_UNDERSCORE STR_N STR_a STR_g STR_r STR_i "\0"
+#define STRING_Syriac0 STR_S STR_y STR_r STR_i STR_a STR_c "\0"
+#define STRING_Tagalog0 STR_T STR_a STR_g STR_a STR_l STR_o STR_g "\0"
+#define STRING_Tagbanwa0 STR_T STR_a STR_g STR_b STR_a STR_n STR_w STR_a "\0"
+#define STRING_Tai_Le0 STR_T STR_a STR_i STR_UNDERSCORE STR_L STR_e "\0"
+#define STRING_Tai_Tham0 STR_T STR_a STR_i STR_UNDERSCORE STR_T STR_h STR_a STR_m "\0"
+#define STRING_Tai_Viet0 STR_T STR_a STR_i STR_UNDERSCORE STR_V STR_i STR_e STR_t "\0"
+#define STRING_Takri0 STR_T STR_a STR_k STR_r STR_i "\0"
+#define STRING_Tamil0 STR_T STR_a STR_m STR_i STR_l "\0"
+#define STRING_Tangut0 STR_T STR_a STR_n STR_g STR_u STR_t "\0"
+#define STRING_Telugu0 STR_T STR_e STR_l STR_u STR_g STR_u "\0"
+#define STRING_Thaana0 STR_T STR_h STR_a STR_a STR_n STR_a "\0"
+#define STRING_Thai0 STR_T STR_h STR_a STR_i "\0"
+#define STRING_Tibetan0 STR_T STR_i STR_b STR_e STR_t STR_a STR_n "\0"
+#define STRING_Tifinagh0 STR_T STR_i STR_f STR_i STR_n STR_a STR_g STR_h "\0"
+#define STRING_Tirhuta0 STR_T STR_i STR_r STR_h STR_u STR_t STR_a "\0"
+#define STRING_Ugaritic0 STR_U STR_g STR_a STR_r STR_i STR_t STR_i STR_c "\0"
+#define STRING_Vai0 STR_V STR_a STR_i "\0"
+#define STRING_Warang_Citi0 STR_W STR_a STR_r STR_a STR_n STR_g STR_UNDERSCORE STR_C STR_i STR_t STR_i "\0"
+#define STRING_Xan0 STR_X STR_a STR_n "\0"
+#define STRING_Xps0 STR_X STR_p STR_s "\0"
+#define STRING_Xsp0 STR_X STR_s STR_p "\0"
+#define STRING_Xuc0 STR_X STR_u STR_c "\0"
+#define STRING_Xwd0 STR_X STR_w STR_d "\0"
+#define STRING_Yi0 STR_Y STR_i "\0"
+#define STRING_Z0 STR_Z "\0"
+#define STRING_Zanabazar_Square0 STR_Z STR_a STR_n STR_a STR_b STR_a STR_z STR_a STR_r STR_UNDERSCORE STR_S STR_q STR_u STR_a STR_r STR_e "\0"
+#define STRING_Zl0 STR_Z STR_l "\0"
+#define STRING_Zp0 STR_Z STR_p "\0"
+#define STRING_Zs0 STR_Z STR_s "\0"
+
+const char PRIV(utt_names)[] =
+ STRING_Adlam0
+ STRING_Ahom0
+ STRING_Anatolian_Hieroglyphs0
+ STRING_Any0
+ STRING_Arabic0
+ STRING_Armenian0
+ STRING_Avestan0
+ STRING_Balinese0
+ STRING_Bamum0
+ STRING_Bassa_Vah0
+ STRING_Batak0
+ STRING_Bengali0
+ STRING_Bhaiksuki0
+ STRING_Bopomofo0
+ STRING_Brahmi0
+ STRING_Braille0
+ STRING_Buginese0
+ STRING_Buhid0
+ STRING_C0
+ STRING_Canadian_Aboriginal0
+ STRING_Carian0
+ STRING_Caucasian_Albanian0
+ STRING_Cc0
+ STRING_Cf0
+ STRING_Chakma0
+ STRING_Cham0
+ STRING_Cherokee0
+ STRING_Cn0
+ STRING_Co0
+ STRING_Common0
+ STRING_Coptic0
+ STRING_Cs0
+ STRING_Cuneiform0
+ STRING_Cypriot0
+ STRING_Cyrillic0
+ STRING_Deseret0
+ STRING_Devanagari0
+ STRING_Dogra0
+ STRING_Duployan0
+ STRING_Egyptian_Hieroglyphs0
+ STRING_Elbasan0
+ STRING_Ethiopic0
+ STRING_Georgian0
+ STRING_Glagolitic0
+ STRING_Gothic0
+ STRING_Grantha0
+ STRING_Greek0
+ STRING_Gujarati0
+ STRING_Gunjala_Gondi0
+ STRING_Gurmukhi0
+ STRING_Han0
+ STRING_Hangul0
+ STRING_Hanifi_Rohingya0
+ STRING_Hanunoo0
+ STRING_Hatran0
+ STRING_Hebrew0
+ STRING_Hiragana0
+ STRING_Imperial_Aramaic0
+ STRING_Inherited0
+ STRING_Inscriptional_Pahlavi0
+ STRING_Inscriptional_Parthian0
+ STRING_Javanese0
+ STRING_Kaithi0
+ STRING_Kannada0
+ STRING_Katakana0
+ STRING_Kayah_Li0
+ STRING_Kharoshthi0
+ STRING_Khmer0
+ STRING_Khojki0
+ STRING_Khudawadi0
+ STRING_L0
+ STRING_L_AMPERSAND0
+ STRING_Lao0
+ STRING_Latin0
+ STRING_Lepcha0
+ STRING_Limbu0
+ STRING_Linear_A0
+ STRING_Linear_B0
+ STRING_Lisu0
+ STRING_Ll0
+ STRING_Lm0
+ STRING_Lo0
+ STRING_Lt0
+ STRING_Lu0
+ STRING_Lycian0
+ STRING_Lydian0
+ STRING_M0
+ STRING_Mahajani0
+ STRING_Makasar0
+ STRING_Malayalam0
+ STRING_Mandaic0
+ STRING_Manichaean0
+ STRING_Marchen0
+ STRING_Masaram_Gondi0
+ STRING_Mc0
+ STRING_Me0
+ STRING_Medefaidrin0
+ STRING_Meetei_Mayek0
+ STRING_Mende_Kikakui0
+ STRING_Meroitic_Cursive0
+ STRING_Meroitic_Hieroglyphs0
+ STRING_Miao0
+ STRING_Mn0
+ STRING_Modi0
+ STRING_Mongolian0
+ STRING_Mro0
+ STRING_Multani0
+ STRING_Myanmar0
+ STRING_N0
+ STRING_Nabataean0
+ STRING_Nd0
+ STRING_New_Tai_Lue0
+ STRING_Newa0
+ STRING_Nko0
+ STRING_Nl0
+ STRING_No0
+ STRING_Nushu0
+ STRING_Ogham0
+ STRING_Ol_Chiki0
+ STRING_Old_Hungarian0
+ STRING_Old_Italic0
+ STRING_Old_North_Arabian0
+ STRING_Old_Permic0
+ STRING_Old_Persian0
+ STRING_Old_Sogdian0
+ STRING_Old_South_Arabian0
+ STRING_Old_Turkic0
+ STRING_Oriya0
+ STRING_Osage0
+ STRING_Osmanya0
+ STRING_P0
+ STRING_Pahawh_Hmong0
+ STRING_Palmyrene0
+ STRING_Pau_Cin_Hau0
+ STRING_Pc0
+ STRING_Pd0
+ STRING_Pe0
+ STRING_Pf0
+ STRING_Phags_Pa0
+ STRING_Phoenician0
+ STRING_Pi0
+ STRING_Po0
+ STRING_Ps0
+ STRING_Psalter_Pahlavi0
+ STRING_Rejang0
+ STRING_Runic0
+ STRING_S0
+ STRING_Samaritan0
+ STRING_Saurashtra0
+ STRING_Sc0
+ STRING_Sharada0
+ STRING_Shavian0
+ STRING_Siddham0
+ STRING_SignWriting0
+ STRING_Sinhala0
+ STRING_Sk0
+ STRING_Sm0
+ STRING_So0
+ STRING_Sogdian0
+ STRING_Sora_Sompeng0
+ STRING_Soyombo0
+ STRING_Sundanese0
+ STRING_Syloti_Nagri0
+ STRING_Syriac0
+ STRING_Tagalog0
+ STRING_Tagbanwa0
+ STRING_Tai_Le0
+ STRING_Tai_Tham0
+ STRING_Tai_Viet0
+ STRING_Takri0
+ STRING_Tamil0
+ STRING_Tangut0
+ STRING_Telugu0
+ STRING_Thaana0
+ STRING_Thai0
+ STRING_Tibetan0
+ STRING_Tifinagh0
+ STRING_Tirhuta0
+ STRING_Ugaritic0
+ STRING_Vai0
+ STRING_Warang_Citi0
+ STRING_Xan0
+ STRING_Xps0
+ STRING_Xsp0
+ STRING_Xuc0
+ STRING_Xwd0
+ STRING_Yi0
+ STRING_Z0
+ STRING_Zanabazar_Square0
+ STRING_Zl0
+ STRING_Zp0
+ STRING_Zs0;
+
+const ucp_type_table PRIV(utt)[] = {
+ { 0, PT_SC, ucp_Adlam },
+ { 6, PT_SC, ucp_Ahom },
+ { 11, PT_SC, ucp_Anatolian_Hieroglyphs },
+ { 33, PT_ANY, 0 },
+ { 37, PT_SC, ucp_Arabic },
+ { 44, PT_SC, ucp_Armenian },
+ { 53, PT_SC, ucp_Avestan },
+ { 61, PT_SC, ucp_Balinese },
+ { 70, PT_SC, ucp_Bamum },
+ { 76, PT_SC, ucp_Bassa_Vah },
+ { 86, PT_SC, ucp_Batak },
+ { 92, PT_SC, ucp_Bengali },
+ { 100, PT_SC, ucp_Bhaiksuki },
+ { 110, PT_SC, ucp_Bopomofo },
+ { 119, PT_SC, ucp_Brahmi },
+ { 126, PT_SC, ucp_Braille },
+ { 134, PT_SC, ucp_Buginese },
+ { 143, PT_SC, ucp_Buhid },
+ { 149, PT_GC, ucp_C },
+ { 151, PT_SC, ucp_Canadian_Aboriginal },
+ { 171, PT_SC, ucp_Carian },
+ { 178, PT_SC, ucp_Caucasian_Albanian },
+ { 197, PT_PC, ucp_Cc },
+ { 200, PT_PC, ucp_Cf },
+ { 203, PT_SC, ucp_Chakma },
+ { 210, PT_SC, ucp_Cham },
+ { 215, PT_SC, ucp_Cherokee },
+ { 224, PT_PC, ucp_Cn },
+ { 227, PT_PC, ucp_Co },
+ { 230, PT_SC, ucp_Common },
+ { 237, PT_SC, ucp_Coptic },
+ { 244, PT_PC, ucp_Cs },
+ { 247, PT_SC, ucp_Cuneiform },
+ { 257, PT_SC, ucp_Cypriot },
+ { 265, PT_SC, ucp_Cyrillic },
+ { 274, PT_SC, ucp_Deseret },
+ { 282, PT_SC, ucp_Devanagari },
+ { 293, PT_SC, ucp_Dogra },
+ { 299, PT_SC, ucp_Duployan },
+ { 308, PT_SC, ucp_Egyptian_Hieroglyphs },
+ { 329, PT_SC, ucp_Elbasan },
+ { 337, PT_SC, ucp_Ethiopic },
+ { 346, PT_SC, ucp_Georgian },
+ { 355, PT_SC, ucp_Glagolitic },
+ { 366, PT_SC, ucp_Gothic },
+ { 373, PT_SC, ucp_Grantha },
+ { 381, PT_SC, ucp_Greek },
+ { 387, PT_SC, ucp_Gujarati },
+ { 396, PT_SC, ucp_Gunjala_Gondi },
+ { 410, PT_SC, ucp_Gurmukhi },
+ { 419, PT_SC, ucp_Han },
+ { 423, PT_SC, ucp_Hangul },
+ { 430, PT_SC, ucp_Hanifi_Rohingya },
+ { 446, PT_SC, ucp_Hanunoo },
+ { 454, PT_SC, ucp_Hatran },
+ { 461, PT_SC, ucp_Hebrew },
+ { 468, PT_SC, ucp_Hiragana },
+ { 477, PT_SC, ucp_Imperial_Aramaic },
+ { 494, PT_SC, ucp_Inherited },
+ { 504, PT_SC, ucp_Inscriptional_Pahlavi },
+ { 526, PT_SC, ucp_Inscriptional_Parthian },
+ { 549, PT_SC, ucp_Javanese },
+ { 558, PT_SC, ucp_Kaithi },
+ { 565, PT_SC, ucp_Kannada },
+ { 573, PT_SC, ucp_Katakana },
+ { 582, PT_SC, ucp_Kayah_Li },
+ { 591, PT_SC, ucp_Kharoshthi },
+ { 602, PT_SC, ucp_Khmer },
+ { 608, PT_SC, ucp_Khojki },
+ { 615, PT_SC, ucp_Khudawadi },
+ { 625, PT_GC, ucp_L },
+ { 627, PT_LAMP, 0 },
+ { 630, PT_SC, ucp_Lao },
+ { 634, PT_SC, ucp_Latin },
+ { 640, PT_SC, ucp_Lepcha },
+ { 647, PT_SC, ucp_Limbu },
+ { 653, PT_SC, ucp_Linear_A },
+ { 662, PT_SC, ucp_Linear_B },
+ { 671, PT_SC, ucp_Lisu },
+ { 676, PT_PC, ucp_Ll },
+ { 679, PT_PC, ucp_Lm },
+ { 682, PT_PC, ucp_Lo },
+ { 685, PT_PC, ucp_Lt },
+ { 688, PT_PC, ucp_Lu },
+ { 691, PT_SC, ucp_Lycian },
+ { 698, PT_SC, ucp_Lydian },
+ { 705, PT_GC, ucp_M },
+ { 707, PT_SC, ucp_Mahajani },
+ { 716, PT_SC, ucp_Makasar },
+ { 724, PT_SC, ucp_Malayalam },
+ { 734, PT_SC, ucp_Mandaic },
+ { 742, PT_SC, ucp_Manichaean },
+ { 753, PT_SC, ucp_Marchen },
+ { 761, PT_SC, ucp_Masaram_Gondi },
+ { 775, PT_PC, ucp_Mc },
+ { 778, PT_PC, ucp_Me },
+ { 781, PT_SC, ucp_Medefaidrin },
+ { 793, PT_SC, ucp_Meetei_Mayek },
+ { 806, PT_SC, ucp_Mende_Kikakui },
+ { 820, PT_SC, ucp_Meroitic_Cursive },
+ { 837, PT_SC, ucp_Meroitic_Hieroglyphs },
+ { 858, PT_SC, ucp_Miao },
+ { 863, PT_PC, ucp_Mn },
+ { 866, PT_SC, ucp_Modi },
+ { 871, PT_SC, ucp_Mongolian },
+ { 881, PT_SC, ucp_Mro },
+ { 885, PT_SC, ucp_Multani },
+ { 893, PT_SC, ucp_Myanmar },
+ { 901, PT_GC, ucp_N },
+ { 903, PT_SC, ucp_Nabataean },
+ { 913, PT_PC, ucp_Nd },
+ { 916, PT_SC, ucp_New_Tai_Lue },
+ { 928, PT_SC, ucp_Newa },
+ { 933, PT_SC, ucp_Nko },
+ { 937, PT_PC, ucp_Nl },
+ { 940, PT_PC, ucp_No },
+ { 943, PT_SC, ucp_Nushu },
+ { 949, PT_SC, ucp_Ogham },
+ { 955, PT_SC, ucp_Ol_Chiki },
+ { 964, PT_SC, ucp_Old_Hungarian },
+ { 978, PT_SC, ucp_Old_Italic },
+ { 989, PT_SC, ucp_Old_North_Arabian },
+ { 1007, PT_SC, ucp_Old_Permic },
+ { 1018, PT_SC, ucp_Old_Persian },
+ { 1030, PT_SC, ucp_Old_Sogdian },
+ { 1042, PT_SC, ucp_Old_South_Arabian },
+ { 1060, PT_SC, ucp_Old_Turkic },
+ { 1071, PT_SC, ucp_Oriya },
+ { 1077, PT_SC, ucp_Osage },
+ { 1083, PT_SC, ucp_Osmanya },
+ { 1091, PT_GC, ucp_P },
+ { 1093, PT_SC, ucp_Pahawh_Hmong },
+ { 1106, PT_SC, ucp_Palmyrene },
+ { 1116, PT_SC, ucp_Pau_Cin_Hau },
+ { 1128, PT_PC, ucp_Pc },
+ { 1131, PT_PC, ucp_Pd },
+ { 1134, PT_PC, ucp_Pe },
+ { 1137, PT_PC, ucp_Pf },
+ { 1140, PT_SC, ucp_Phags_Pa },
+ { 1149, PT_SC, ucp_Phoenician },
+ { 1160, PT_PC, ucp_Pi },
+ { 1163, PT_PC, ucp_Po },
+ { 1166, PT_PC, ucp_Ps },
+ { 1169, PT_SC, ucp_Psalter_Pahlavi },
+ { 1185, PT_SC, ucp_Rejang },
+ { 1192, PT_SC, ucp_Runic },
+ { 1198, PT_GC, ucp_S },
+ { 1200, PT_SC, ucp_Samaritan },
+ { 1210, PT_SC, ucp_Saurashtra },
+ { 1221, PT_PC, ucp_Sc },
+ { 1224, PT_SC, ucp_Sharada },
+ { 1232, PT_SC, ucp_Shavian },
+ { 1240, PT_SC, ucp_Siddham },
+ { 1248, PT_SC, ucp_SignWriting },
+ { 1260, PT_SC, ucp_Sinhala },
+ { 1268, PT_PC, ucp_Sk },
+ { 1271, PT_PC, ucp_Sm },
+ { 1274, PT_PC, ucp_So },
+ { 1277, PT_SC, ucp_Sogdian },
+ { 1285, PT_SC, ucp_Sora_Sompeng },
+ { 1298, PT_SC, ucp_Soyombo },
+ { 1306, PT_SC, ucp_Sundanese },
+ { 1316, PT_SC, ucp_Syloti_Nagri },
+ { 1329, PT_SC, ucp_Syriac },
+ { 1336, PT_SC, ucp_Tagalog },
+ { 1344, PT_SC, ucp_Tagbanwa },
+ { 1353, PT_SC, ucp_Tai_Le },
+ { 1360, PT_SC, ucp_Tai_Tham },
+ { 1369, PT_SC, ucp_Tai_Viet },
+ { 1378, PT_SC, ucp_Takri },
+ { 1384, PT_SC, ucp_Tamil },
+ { 1390, PT_SC, ucp_Tangut },
+ { 1397, PT_SC, ucp_Telugu },
+ { 1404, PT_SC, ucp_Thaana },
+ { 1411, PT_SC, ucp_Thai },
+ { 1416, PT_SC, ucp_Tibetan },
+ { 1424, PT_SC, ucp_Tifinagh },
+ { 1433, PT_SC, ucp_Tirhuta },
+ { 1441, PT_SC, ucp_Ugaritic },
+ { 1450, PT_SC, ucp_Vai },
+ { 1454, PT_SC, ucp_Warang_Citi },
+ { 1466, PT_ALNUM, 0 },
+ { 1470, PT_PXSPACE, 0 },
+ { 1474, PT_SPACE, 0 },
+ { 1478, PT_UCNC, 0 },
+ { 1482, PT_WORD, 0 },
+ { 1486, PT_SC, ucp_Yi },
+ { 1489, PT_GC, ucp_Z },
+ { 1491, PT_SC, ucp_Zanabazar_Square },
+ { 1508, PT_PC, ucp_Zl },
+ { 1511, PT_PC, ucp_Zp },
+ { 1514, PT_PC, ucp_Zs }
+};
+
+const size_t PRIV(utt_size) = sizeof(PRIV(utt)) / sizeof(ucp_type_table);
+
+#endif /* SUPPORT_UNICODE */
+
+/* End of pcre2_tables.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_ucd.c b/test/monniaux/pcre2-10.32/pcre2_ucd.c
new file mode 100644
index 00000000..275a4be2
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_ucd.c
@@ -0,0 +1,4189 @@
+/* This module is generated by the maint/MultiStage2.py script.
+Do not modify it by hand. Instead modify the script and run it
+to regenerate this code.
+
+As well as being part of the PCRE2 library, this module is #included
+by the pcre2test program, which redefines the PRIV macro to change
+table names from _pcre2_xxx to xxxx, thereby avoiding name clashes
+with the library. At present, just one of these tables is actually
+needed. */
+
+#ifndef PCRE2_PCRE2TEST
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pcre2_internal.h"
+
+#endif /* PCRE2_PCRE2TEST */
+
+/* Unicode character database. */
+/* This file was autogenerated by the MultiStage2.py script. */
+/* Total size: 92592 bytes, block size: 128. */
+
+/* The tables herein are needed only when UCP support is built,
+and in PCRE2 that happens automatically with UTF support.
+This module should not be referenced otherwise, so
+it should not matter whether it is compiled or not. However
+a comment was received about space saving - maybe the guy linked
+all the modules rather than using a library - so we include a
+condition to cut out the tables when not needed. But don't leave
+a totally empty module because some compilers barf at that.
+Instead, just supply small dummy tables. */
+
+#ifndef SUPPORT_UNICODE
+const ucd_record PRIV(ucd_records)[] = {{0,0,0,0,0 }};
+const uint16_t PRIV(ucd_stage1)[] = {0};
+const uint16_t PRIV(ucd_stage2)[] = {0};
+const uint32_t PRIV(ucd_caseless_sets)[] = {0};
+#else
+
+const char *PRIV(unicode_version) = "11.0.0";
+
+/* If the 32-bit library is run in non-32-bit mode, character values
+greater than 0x10ffff may be encountered. For these we set up a
+special record. */
+
+#if PCRE2_CODE_UNIT_WIDTH == 32
+const ucd_record PRIV(dummy_ucd_record)[] = {{
+ ucp_Common, /* script */
+ ucp_Cn, /* type unassigned */
+ ucp_gbOther, /* grapheme break property */
+ 0, /* case set */
+ 0, /* other case */
+ }};
+#endif
+
+/* When recompiling tables with a new Unicode version, please check the
+types in this structure definition from pcre2_internal.h (the actual
+field names will be different):
+
+typedef struct {
+uint8_t property_0;
+uint8_t property_1;
+uint8_t property_2;
+uint8_t property_3;
+pcre_int32 property_4;
+} ucd_record;
+*/
+
+
+const uint32_t PRIV(ucd_caseless_sets)[] = {
+ NOTACHAR,
+ 0x0053, 0x0073, 0x017f, NOTACHAR,
+ 0x01c4, 0x01c5, 0x01c6, NOTACHAR,
+ 0x01c7, 0x01c8, 0x01c9, NOTACHAR,
+ 0x01ca, 0x01cb, 0x01cc, NOTACHAR,
+ 0x01f1, 0x01f2, 0x01f3, NOTACHAR,
+ 0x0345, 0x0399, 0x03b9, 0x1fbe, NOTACHAR,
+ 0x00b5, 0x039c, 0x03bc, NOTACHAR,
+ 0x03a3, 0x03c2, 0x03c3, NOTACHAR,
+ 0x0392, 0x03b2, 0x03d0, NOTACHAR,
+ 0x0398, 0x03b8, 0x03d1, 0x03f4, NOTACHAR,
+ 0x03a6, 0x03c6, 0x03d5, NOTACHAR,
+ 0x03a0, 0x03c0, 0x03d6, NOTACHAR,
+ 0x039a, 0x03ba, 0x03f0, NOTACHAR,
+ 0x03a1, 0x03c1, 0x03f1, NOTACHAR,
+ 0x0395, 0x03b5, 0x03f5, NOTACHAR,
+ 0x0412, 0x0432, 0x1c80, NOTACHAR,
+ 0x0414, 0x0434, 0x1c81, NOTACHAR,
+ 0x041e, 0x043e, 0x1c82, NOTACHAR,
+ 0x0421, 0x0441, 0x1c83, NOTACHAR,
+ 0x0422, 0x0442, 0x1c84, 0x1c85, NOTACHAR,
+ 0x042a, 0x044a, 0x1c86, NOTACHAR,
+ 0x0462, 0x0463, 0x1c87, NOTACHAR,
+ 0x1e60, 0x1e61, 0x1e9b, NOTACHAR,
+ 0x03a9, 0x03c9, 0x2126, NOTACHAR,
+ 0x004b, 0x006b, 0x212a, NOTACHAR,
+ 0x00c5, 0x00e5, 0x212b, NOTACHAR,
+ 0x1c88, 0xa64a, 0xa64b, NOTACHAR,
+};
+
+/* When #included in pcre2test, we don't need this large table. */
+
+#ifndef PCRE2_PCRE2TEST
+
+const ucd_record PRIV(ucd_records)[] = { /* 6832 bytes, record size 8 */
+ { 9, 0, 2, 0, 0, }, /* 0 */
+ { 9, 0, 1, 0, 0, }, /* 1 */
+ { 9, 0, 0, 0, 0, }, /* 2 */
+ { 9, 29, 12, 0, 0, }, /* 3 */
+ { 9, 21, 12, 0, 0, }, /* 4 */
+ { 9, 23, 12, 0, 0, }, /* 5 */
+ { 9, 22, 12, 0, 0, }, /* 6 */
+ { 9, 18, 12, 0, 0, }, /* 7 */
+ { 9, 25, 12, 0, 0, }, /* 8 */
+ { 9, 17, 12, 0, 0, }, /* 9 */
+ { 9, 13, 12, 0, 0, }, /* 10 */
+ { 33, 9, 12, 0, 32, }, /* 11 */
+ { 33, 9, 12, 100, 32, }, /* 12 */
+ { 33, 9, 12, 1, 32, }, /* 13 */
+ { 9, 24, 12, 0, 0, }, /* 14 */
+ { 9, 16, 12, 0, 0, }, /* 15 */
+ { 33, 5, 12, 0, -32, }, /* 16 */
+ { 33, 5, 12, 100, -32, }, /* 17 */
+ { 33, 5, 12, 1, -32, }, /* 18 */
+ { 9, 26, 12, 0, 0, }, /* 19 */
+ { 9, 26, 14, 0, 0, }, /* 20 */
+ { 33, 7, 12, 0, 0, }, /* 21 */
+ { 9, 20, 12, 0, 0, }, /* 22 */
+ { 9, 1, 2, 0, 0, }, /* 23 */
+ { 9, 15, 12, 0, 0, }, /* 24 */
+ { 9, 5, 12, 26, 775, }, /* 25 */
+ { 9, 19, 12, 0, 0, }, /* 26 */
+ { 33, 9, 12, 104, 32, }, /* 27 */
+ { 33, 5, 12, 0, 7615, }, /* 28 */
+ { 33, 5, 12, 104, -32, }, /* 29 */
+ { 33, 5, 12, 0, 121, }, /* 30 */
+ { 33, 9, 12, 0, 1, }, /* 31 */
+ { 33, 5, 12, 0, -1, }, /* 32 */
+ { 33, 9, 12, 0, 0, }, /* 33 */
+ { 33, 5, 12, 0, 0, }, /* 34 */
+ { 33, 9, 12, 0, -121, }, /* 35 */
+ { 33, 5, 12, 1, -268, }, /* 36 */
+ { 33, 5, 12, 0, 195, }, /* 37 */
+ { 33, 9, 12, 0, 210, }, /* 38 */
+ { 33, 9, 12, 0, 206, }, /* 39 */
+ { 33, 9, 12, 0, 205, }, /* 40 */
+ { 33, 9, 12, 0, 79, }, /* 41 */
+ { 33, 9, 12, 0, 202, }, /* 42 */
+ { 33, 9, 12, 0, 203, }, /* 43 */
+ { 33, 9, 12, 0, 207, }, /* 44 */
+ { 33, 5, 12, 0, 97, }, /* 45 */
+ { 33, 9, 12, 0, 211, }, /* 46 */
+ { 33, 9, 12, 0, 209, }, /* 47 */
+ { 33, 5, 12, 0, 163, }, /* 48 */
+ { 33, 9, 12, 0, 213, }, /* 49 */
+ { 33, 5, 12, 0, 130, }, /* 50 */
+ { 33, 9, 12, 0, 214, }, /* 51 */
+ { 33, 9, 12, 0, 218, }, /* 52 */
+ { 33, 9, 12, 0, 217, }, /* 53 */
+ { 33, 9, 12, 0, 219, }, /* 54 */
+ { 33, 5, 12, 0, 56, }, /* 55 */
+ { 33, 9, 12, 5, 2, }, /* 56 */
+ { 33, 8, 12, 5, 1, }, /* 57 */
+ { 33, 5, 12, 5, -2, }, /* 58 */
+ { 33, 9, 12, 9, 2, }, /* 59 */
+ { 33, 8, 12, 9, 1, }, /* 60 */
+ { 33, 5, 12, 9, -2, }, /* 61 */
+ { 33, 9, 12, 13, 2, }, /* 62 */
+ { 33, 8, 12, 13, 1, }, /* 63 */
+ { 33, 5, 12, 13, -2, }, /* 64 */
+ { 33, 5, 12, 0, -79, }, /* 65 */
+ { 33, 9, 12, 17, 2, }, /* 66 */
+ { 33, 8, 12, 17, 1, }, /* 67 */
+ { 33, 5, 12, 17, -2, }, /* 68 */
+ { 33, 9, 12, 0, -97, }, /* 69 */
+ { 33, 9, 12, 0, -56, }, /* 70 */
+ { 33, 9, 12, 0, -130, }, /* 71 */
+ { 33, 9, 12, 0, 10795, }, /* 72 */
+ { 33, 9, 12, 0, -163, }, /* 73 */
+ { 33, 9, 12, 0, 10792, }, /* 74 */
+ { 33, 5, 12, 0, 10815, }, /* 75 */
+ { 33, 9, 12, 0, -195, }, /* 76 */
+ { 33, 9, 12, 0, 69, }, /* 77 */
+ { 33, 9, 12, 0, 71, }, /* 78 */
+ { 33, 5, 12, 0, 10783, }, /* 79 */
+ { 33, 5, 12, 0, 10780, }, /* 80 */
+ { 33, 5, 12, 0, 10782, }, /* 81 */
+ { 33, 5, 12, 0, -210, }, /* 82 */
+ { 33, 5, 12, 0, -206, }, /* 83 */
+ { 33, 5, 12, 0, -205, }, /* 84 */
+ { 33, 5, 12, 0, -202, }, /* 85 */
+ { 33, 5, 12, 0, -203, }, /* 86 */
+ { 33, 5, 12, 0, 42319, }, /* 87 */
+ { 33, 5, 12, 0, 42315, }, /* 88 */
+ { 33, 5, 12, 0, -207, }, /* 89 */
+ { 33, 5, 12, 0, 42280, }, /* 90 */
+ { 33, 5, 12, 0, 42308, }, /* 91 */
+ { 33, 5, 12, 0, -209, }, /* 92 */
+ { 33, 5, 12, 0, -211, }, /* 93 */
+ { 33, 5, 12, 0, 10743, }, /* 94 */
+ { 33, 5, 12, 0, 42305, }, /* 95 */
+ { 33, 5, 12, 0, 10749, }, /* 96 */
+ { 33, 5, 12, 0, -213, }, /* 97 */
+ { 33, 5, 12, 0, -214, }, /* 98 */
+ { 33, 5, 12, 0, 10727, }, /* 99 */
+ { 33, 5, 12, 0, -218, }, /* 100 */
+ { 33, 5, 12, 0, 42282, }, /* 101 */
+ { 33, 5, 12, 0, -69, }, /* 102 */
+ { 33, 5, 12, 0, -217, }, /* 103 */
+ { 33, 5, 12, 0, -71, }, /* 104 */
+ { 33, 5, 12, 0, -219, }, /* 105 */
+ { 33, 5, 12, 0, 42261, }, /* 106 */
+ { 33, 5, 12, 0, 42258, }, /* 107 */
+ { 33, 6, 12, 0, 0, }, /* 108 */
+ { 9, 6, 12, 0, 0, }, /* 109 */
+ { 3, 24, 12, 0, 0, }, /* 110 */
+ { 27, 12, 3, 0, 0, }, /* 111 */
+ { 27, 12, 3, 21, 116, }, /* 112 */
+ { 19, 9, 12, 0, 1, }, /* 113 */
+ { 19, 5, 12, 0, -1, }, /* 114 */
+ { 19, 24, 12, 0, 0, }, /* 115 */
+ { 9, 2, 12, 0, 0, }, /* 116 */
+ { 19, 6, 12, 0, 0, }, /* 117 */
+ { 19, 5, 12, 0, 130, }, /* 118 */
+ { 19, 9, 12, 0, 116, }, /* 119 */
+ { 19, 9, 12, 0, 38, }, /* 120 */
+ { 19, 9, 12, 0, 37, }, /* 121 */
+ { 19, 9, 12, 0, 64, }, /* 122 */
+ { 19, 9, 12, 0, 63, }, /* 123 */
+ { 19, 5, 12, 0, 0, }, /* 124 */
+ { 19, 9, 12, 0, 32, }, /* 125 */
+ { 19, 9, 12, 34, 32, }, /* 126 */
+ { 19, 9, 12, 59, 32, }, /* 127 */
+ { 19, 9, 12, 38, 32, }, /* 128 */
+ { 19, 9, 12, 21, 32, }, /* 129 */
+ { 19, 9, 12, 51, 32, }, /* 130 */
+ { 19, 9, 12, 26, 32, }, /* 131 */
+ { 19, 9, 12, 47, 32, }, /* 132 */
+ { 19, 9, 12, 55, 32, }, /* 133 */
+ { 19, 9, 12, 30, 32, }, /* 134 */
+ { 19, 9, 12, 43, 32, }, /* 135 */
+ { 19, 9, 12, 96, 32, }, /* 136 */
+ { 19, 5, 12, 0, -38, }, /* 137 */
+ { 19, 5, 12, 0, -37, }, /* 138 */
+ { 19, 5, 12, 0, -32, }, /* 139 */
+ { 19, 5, 12, 34, -32, }, /* 140 */
+ { 19, 5, 12, 59, -32, }, /* 141 */
+ { 19, 5, 12, 38, -32, }, /* 142 */
+ { 19, 5, 12, 21, -116, }, /* 143 */
+ { 19, 5, 12, 51, -32, }, /* 144 */
+ { 19, 5, 12, 26, -775, }, /* 145 */
+ { 19, 5, 12, 47, -32, }, /* 146 */
+ { 19, 5, 12, 55, -32, }, /* 147 */
+ { 19, 5, 12, 30, 1, }, /* 148 */
+ { 19, 5, 12, 30, -32, }, /* 149 */
+ { 19, 5, 12, 43, -32, }, /* 150 */
+ { 19, 5, 12, 96, -32, }, /* 151 */
+ { 19, 5, 12, 0, -64, }, /* 152 */
+ { 19, 5, 12, 0, -63, }, /* 153 */
+ { 19, 9, 12, 0, 8, }, /* 154 */
+ { 19, 5, 12, 34, -30, }, /* 155 */
+ { 19, 5, 12, 38, -25, }, /* 156 */
+ { 19, 9, 12, 0, 0, }, /* 157 */
+ { 19, 5, 12, 43, -15, }, /* 158 */
+ { 19, 5, 12, 47, -22, }, /* 159 */
+ { 19, 5, 12, 0, -8, }, /* 160 */
+ { 10, 9, 12, 0, 1, }, /* 161 */
+ { 10, 5, 12, 0, -1, }, /* 162 */
+ { 19, 5, 12, 51, -54, }, /* 163 */
+ { 19, 5, 12, 55, -48, }, /* 164 */
+ { 19, 5, 12, 0, 7, }, /* 165 */
+ { 19, 5, 12, 0, -116, }, /* 166 */
+ { 19, 9, 12, 38, -60, }, /* 167 */
+ { 19, 5, 12, 59, -64, }, /* 168 */
+ { 19, 25, 12, 0, 0, }, /* 169 */
+ { 19, 9, 12, 0, -7, }, /* 170 */
+ { 19, 9, 12, 0, -130, }, /* 171 */
+ { 12, 9, 12, 0, 80, }, /* 172 */
+ { 12, 9, 12, 0, 32, }, /* 173 */
+ { 12, 9, 12, 63, 32, }, /* 174 */
+ { 12, 9, 12, 67, 32, }, /* 175 */
+ { 12, 9, 12, 71, 32, }, /* 176 */
+ { 12, 9, 12, 75, 32, }, /* 177 */
+ { 12, 9, 12, 79, 32, }, /* 178 */
+ { 12, 9, 12, 84, 32, }, /* 179 */
+ { 12, 5, 12, 0, -32, }, /* 180 */
+ { 12, 5, 12, 63, -32, }, /* 181 */
+ { 12, 5, 12, 67, -32, }, /* 182 */
+ { 12, 5, 12, 71, -32, }, /* 183 */
+ { 12, 5, 12, 75, -32, }, /* 184 */
+ { 12, 5, 12, 79, -32, }, /* 185 */
+ { 12, 5, 12, 84, -32, }, /* 186 */
+ { 12, 5, 12, 0, -80, }, /* 187 */
+ { 12, 9, 12, 0, 1, }, /* 188 */
+ { 12, 5, 12, 0, -1, }, /* 189 */
+ { 12, 9, 12, 88, 1, }, /* 190 */
+ { 12, 5, 12, 88, -1, }, /* 191 */
+ { 12, 26, 12, 0, 0, }, /* 192 */
+ { 12, 12, 3, 0, 0, }, /* 193 */
+ { 12, 11, 3, 0, 0, }, /* 194 */
+ { 12, 9, 12, 0, 15, }, /* 195 */
+ { 12, 5, 12, 0, -15, }, /* 196 */
+ { 1, 9, 12, 0, 48, }, /* 197 */
+ { 1, 6, 12, 0, 0, }, /* 198 */
+ { 1, 21, 12, 0, 0, }, /* 199 */
+ { 1, 5, 12, 0, 0, }, /* 200 */
+ { 1, 5, 12, 0, -48, }, /* 201 */
+ { 1, 17, 12, 0, 0, }, /* 202 */
+ { 1, 26, 12, 0, 0, }, /* 203 */
+ { 1, 23, 12, 0, 0, }, /* 204 */
+ { 25, 12, 3, 0, 0, }, /* 205 */
+ { 25, 17, 12, 0, 0, }, /* 206 */
+ { 25, 21, 12, 0, 0, }, /* 207 */
+ { 25, 7, 12, 0, 0, }, /* 208 */
+ { 0, 1, 4, 0, 0, }, /* 209 */
+ { 9, 1, 4, 0, 0, }, /* 210 */
+ { 0, 25, 12, 0, 0, }, /* 211 */
+ { 0, 21, 12, 0, 0, }, /* 212 */
+ { 0, 23, 12, 0, 0, }, /* 213 */
+ { 0, 26, 12, 0, 0, }, /* 214 */
+ { 0, 12, 3, 0, 0, }, /* 215 */
+ { 0, 1, 2, 0, 0, }, /* 216 */
+ { 0, 7, 12, 0, 0, }, /* 217 */
+ { 0, 13, 12, 0, 0, }, /* 218 */
+ { 0, 6, 12, 0, 0, }, /* 219 */
+ { 49, 21, 12, 0, 0, }, /* 220 */
+ { 49, 1, 4, 0, 0, }, /* 221 */
+ { 49, 7, 12, 0, 0, }, /* 222 */
+ { 49, 12, 3, 0, 0, }, /* 223 */
+ { 55, 7, 12, 0, 0, }, /* 224 */
+ { 55, 12, 3, 0, 0, }, /* 225 */
+ { 63, 13, 12, 0, 0, }, /* 226 */
+ { 63, 7, 12, 0, 0, }, /* 227 */
+ { 63, 12, 3, 0, 0, }, /* 228 */
+ { 63, 6, 12, 0, 0, }, /* 229 */
+ { 63, 26, 12, 0, 0, }, /* 230 */
+ { 63, 21, 12, 0, 0, }, /* 231 */
+ { 63, 23, 12, 0, 0, }, /* 232 */
+ { 89, 7, 12, 0, 0, }, /* 233 */
+ { 89, 12, 3, 0, 0, }, /* 234 */
+ { 89, 6, 12, 0, 0, }, /* 235 */
+ { 89, 21, 12, 0, 0, }, /* 236 */
+ { 94, 7, 12, 0, 0, }, /* 237 */
+ { 94, 12, 3, 0, 0, }, /* 238 */
+ { 94, 21, 12, 0, 0, }, /* 239 */
+ { 14, 12, 3, 0, 0, }, /* 240 */
+ { 14, 10, 5, 0, 0, }, /* 241 */
+ { 14, 7, 12, 0, 0, }, /* 242 */
+ { 14, 13, 12, 0, 0, }, /* 243 */
+ { 14, 21, 12, 0, 0, }, /* 244 */
+ { 14, 6, 12, 0, 0, }, /* 245 */
+ { 2, 7, 12, 0, 0, }, /* 246 */
+ { 2, 12, 3, 0, 0, }, /* 247 */
+ { 2, 10, 5, 0, 0, }, /* 248 */
+ { 2, 10, 3, 0, 0, }, /* 249 */
+ { 2, 13, 12, 0, 0, }, /* 250 */
+ { 2, 23, 12, 0, 0, }, /* 251 */
+ { 2, 15, 12, 0, 0, }, /* 252 */
+ { 2, 26, 12, 0, 0, }, /* 253 */
+ { 2, 21, 12, 0, 0, }, /* 254 */
+ { 21, 12, 3, 0, 0, }, /* 255 */
+ { 21, 10, 5, 0, 0, }, /* 256 */
+ { 21, 7, 12, 0, 0, }, /* 257 */
+ { 21, 13, 12, 0, 0, }, /* 258 */
+ { 21, 21, 12, 0, 0, }, /* 259 */
+ { 20, 12, 3, 0, 0, }, /* 260 */
+ { 20, 10, 5, 0, 0, }, /* 261 */
+ { 20, 7, 12, 0, 0, }, /* 262 */
+ { 20, 13, 12, 0, 0, }, /* 263 */
+ { 20, 21, 12, 0, 0, }, /* 264 */
+ { 20, 23, 12, 0, 0, }, /* 265 */
+ { 43, 12, 3, 0, 0, }, /* 266 */
+ { 43, 10, 5, 0, 0, }, /* 267 */
+ { 43, 7, 12, 0, 0, }, /* 268 */
+ { 43, 10, 3, 0, 0, }, /* 269 */
+ { 43, 13, 12, 0, 0, }, /* 270 */
+ { 43, 26, 12, 0, 0, }, /* 271 */
+ { 43, 15, 12, 0, 0, }, /* 272 */
+ { 53, 12, 3, 0, 0, }, /* 273 */
+ { 53, 7, 12, 0, 0, }, /* 274 */
+ { 53, 10, 3, 0, 0, }, /* 275 */
+ { 53, 10, 5, 0, 0, }, /* 276 */
+ { 53, 13, 12, 0, 0, }, /* 277 */
+ { 53, 15, 12, 0, 0, }, /* 278 */
+ { 53, 26, 12, 0, 0, }, /* 279 */
+ { 53, 23, 12, 0, 0, }, /* 280 */
+ { 54, 12, 3, 0, 0, }, /* 281 */
+ { 54, 10, 5, 0, 0, }, /* 282 */
+ { 54, 7, 12, 0, 0, }, /* 283 */
+ { 54, 13, 12, 0, 0, }, /* 284 */
+ { 54, 15, 12, 0, 0, }, /* 285 */
+ { 54, 26, 12, 0, 0, }, /* 286 */
+ { 28, 7, 12, 0, 0, }, /* 287 */
+ { 28, 12, 3, 0, 0, }, /* 288 */
+ { 28, 10, 5, 0, 0, }, /* 289 */
+ { 28, 21, 12, 0, 0, }, /* 290 */
+ { 28, 10, 3, 0, 0, }, /* 291 */
+ { 28, 13, 12, 0, 0, }, /* 292 */
+ { 36, 12, 3, 0, 0, }, /* 293 */
+ { 36, 10, 5, 0, 0, }, /* 294 */
+ { 36, 7, 12, 0, 0, }, /* 295 */
+ { 36, 10, 3, 0, 0, }, /* 296 */
+ { 36, 7, 4, 0, 0, }, /* 297 */
+ { 36, 26, 12, 0, 0, }, /* 298 */
+ { 36, 15, 12, 0, 0, }, /* 299 */
+ { 36, 13, 12, 0, 0, }, /* 300 */
+ { 47, 10, 5, 0, 0, }, /* 301 */
+ { 47, 7, 12, 0, 0, }, /* 302 */
+ { 47, 12, 3, 0, 0, }, /* 303 */
+ { 47, 10, 3, 0, 0, }, /* 304 */
+ { 47, 13, 12, 0, 0, }, /* 305 */
+ { 47, 21, 12, 0, 0, }, /* 306 */
+ { 56, 7, 12, 0, 0, }, /* 307 */
+ { 56, 12, 3, 0, 0, }, /* 308 */
+ { 56, 7, 5, 0, 0, }, /* 309 */
+ { 56, 6, 12, 0, 0, }, /* 310 */
+ { 56, 21, 12, 0, 0, }, /* 311 */
+ { 56, 13, 12, 0, 0, }, /* 312 */
+ { 32, 7, 12, 0, 0, }, /* 313 */
+ { 32, 12, 3, 0, 0, }, /* 314 */
+ { 32, 7, 5, 0, 0, }, /* 315 */
+ { 32, 6, 12, 0, 0, }, /* 316 */
+ { 32, 13, 12, 0, 0, }, /* 317 */
+ { 57, 7, 12, 0, 0, }, /* 318 */
+ { 57, 26, 12, 0, 0, }, /* 319 */
+ { 57, 21, 12, 0, 0, }, /* 320 */
+ { 57, 12, 3, 0, 0, }, /* 321 */
+ { 57, 13, 12, 0, 0, }, /* 322 */
+ { 57, 15, 12, 0, 0, }, /* 323 */
+ { 57, 22, 12, 0, 0, }, /* 324 */
+ { 57, 18, 12, 0, 0, }, /* 325 */
+ { 57, 10, 5, 0, 0, }, /* 326 */
+ { 38, 7, 12, 0, 0, }, /* 327 */
+ { 38, 10, 12, 0, 0, }, /* 328 */
+ { 38, 12, 3, 0, 0, }, /* 329 */
+ { 38, 10, 5, 0, 0, }, /* 330 */
+ { 38, 13, 12, 0, 0, }, /* 331 */
+ { 38, 21, 12, 0, 0, }, /* 332 */
+ { 38, 26, 12, 0, 0, }, /* 333 */
+ { 16, 9, 12, 0, 7264, }, /* 334 */
+ { 16, 5, 12, 0, 3008, }, /* 335 */
+ { 16, 6, 12, 0, 0, }, /* 336 */
+ { 23, 7, 6, 0, 0, }, /* 337 */
+ { 23, 7, 7, 0, 0, }, /* 338 */
+ { 23, 7, 8, 0, 0, }, /* 339 */
+ { 15, 7, 12, 0, 0, }, /* 340 */
+ { 15, 12, 3, 0, 0, }, /* 341 */
+ { 15, 21, 12, 0, 0, }, /* 342 */
+ { 15, 15, 12, 0, 0, }, /* 343 */
+ { 15, 26, 12, 0, 0, }, /* 344 */
+ { 8, 9, 12, 0, 38864, }, /* 345 */
+ { 8, 9, 12, 0, 8, }, /* 346 */
+ { 8, 5, 12, 0, -8, }, /* 347 */
+ { 7, 17, 12, 0, 0, }, /* 348 */
+ { 7, 7, 12, 0, 0, }, /* 349 */
+ { 7, 21, 12, 0, 0, }, /* 350 */
+ { 40, 29, 12, 0, 0, }, /* 351 */
+ { 40, 7, 12, 0, 0, }, /* 352 */
+ { 40, 22, 12, 0, 0, }, /* 353 */
+ { 40, 18, 12, 0, 0, }, /* 354 */
+ { 45, 7, 12, 0, 0, }, /* 355 */
+ { 45, 14, 12, 0, 0, }, /* 356 */
+ { 50, 7, 12, 0, 0, }, /* 357 */
+ { 50, 12, 3, 0, 0, }, /* 358 */
+ { 24, 7, 12, 0, 0, }, /* 359 */
+ { 24, 12, 3, 0, 0, }, /* 360 */
+ { 6, 7, 12, 0, 0, }, /* 361 */
+ { 6, 12, 3, 0, 0, }, /* 362 */
+ { 51, 7, 12, 0, 0, }, /* 363 */
+ { 51, 12, 3, 0, 0, }, /* 364 */
+ { 31, 7, 12, 0, 0, }, /* 365 */
+ { 31, 12, 3, 0, 0, }, /* 366 */
+ { 31, 10, 5, 0, 0, }, /* 367 */
+ { 31, 21, 12, 0, 0, }, /* 368 */
+ { 31, 6, 12, 0, 0, }, /* 369 */
+ { 31, 23, 12, 0, 0, }, /* 370 */
+ { 31, 13, 12, 0, 0, }, /* 371 */
+ { 31, 15, 12, 0, 0, }, /* 372 */
+ { 37, 21, 12, 0, 0, }, /* 373 */
+ { 37, 17, 12, 0, 0, }, /* 374 */
+ { 37, 12, 3, 0, 0, }, /* 375 */
+ { 37, 1, 2, 0, 0, }, /* 376 */
+ { 37, 13, 12, 0, 0, }, /* 377 */
+ { 37, 7, 12, 0, 0, }, /* 378 */
+ { 37, 6, 12, 0, 0, }, /* 379 */
+ { 34, 7, 12, 0, 0, }, /* 380 */
+ { 34, 12, 3, 0, 0, }, /* 381 */
+ { 34, 10, 5, 0, 0, }, /* 382 */
+ { 34, 26, 12, 0, 0, }, /* 383 */
+ { 34, 21, 12, 0, 0, }, /* 384 */
+ { 34, 13, 12, 0, 0, }, /* 385 */
+ { 52, 7, 12, 0, 0, }, /* 386 */
+ { 39, 7, 12, 0, 0, }, /* 387 */
+ { 39, 13, 12, 0, 0, }, /* 388 */
+ { 39, 15, 12, 0, 0, }, /* 389 */
+ { 39, 26, 12, 0, 0, }, /* 390 */
+ { 31, 26, 12, 0, 0, }, /* 391 */
+ { 5, 7, 12, 0, 0, }, /* 392 */
+ { 5, 12, 3, 0, 0, }, /* 393 */
+ { 5, 10, 5, 0, 0, }, /* 394 */
+ { 5, 21, 12, 0, 0, }, /* 395 */
+ { 90, 7, 12, 0, 0, }, /* 396 */
+ { 90, 10, 5, 0, 0, }, /* 397 */
+ { 90, 12, 3, 0, 0, }, /* 398 */
+ { 90, 10, 12, 0, 0, }, /* 399 */
+ { 90, 13, 12, 0, 0, }, /* 400 */
+ { 90, 21, 12, 0, 0, }, /* 401 */
+ { 90, 6, 12, 0, 0, }, /* 402 */
+ { 27, 11, 3, 0, 0, }, /* 403 */
+ { 61, 12, 3, 0, 0, }, /* 404 */
+ { 61, 10, 5, 0, 0, }, /* 405 */
+ { 61, 7, 12, 0, 0, }, /* 406 */
+ { 61, 13, 12, 0, 0, }, /* 407 */
+ { 61, 21, 12, 0, 0, }, /* 408 */
+ { 61, 26, 12, 0, 0, }, /* 409 */
+ { 75, 12, 3, 0, 0, }, /* 410 */
+ { 75, 10, 5, 0, 0, }, /* 411 */
+ { 75, 7, 12, 0, 0, }, /* 412 */
+ { 75, 13, 12, 0, 0, }, /* 413 */
+ { 92, 7, 12, 0, 0, }, /* 414 */
+ { 92, 12, 3, 0, 0, }, /* 415 */
+ { 92, 10, 5, 0, 0, }, /* 416 */
+ { 92, 21, 12, 0, 0, }, /* 417 */
+ { 69, 7, 12, 0, 0, }, /* 418 */
+ { 69, 10, 5, 0, 0, }, /* 419 */
+ { 69, 12, 3, 0, 0, }, /* 420 */
+ { 69, 21, 12, 0, 0, }, /* 421 */
+ { 69, 13, 12, 0, 0, }, /* 422 */
+ { 72, 13, 12, 0, 0, }, /* 423 */
+ { 72, 7, 12, 0, 0, }, /* 424 */
+ { 72, 6, 12, 0, 0, }, /* 425 */
+ { 72, 21, 12, 0, 0, }, /* 426 */
+ { 12, 5, 12, 63, -6222, }, /* 427 */
+ { 12, 5, 12, 67, -6221, }, /* 428 */
+ { 12, 5, 12, 71, -6212, }, /* 429 */
+ { 12, 5, 12, 75, -6210, }, /* 430 */
+ { 12, 5, 12, 79, -6210, }, /* 431 */
+ { 12, 5, 12, 79, -6211, }, /* 432 */
+ { 12, 5, 12, 84, -6204, }, /* 433 */
+ { 12, 5, 12, 88, -6180, }, /* 434 */
+ { 12, 5, 12, 108, 35267, }, /* 435 */
+ { 16, 9, 12, 0, -3008, }, /* 436 */
+ { 75, 21, 12, 0, 0, }, /* 437 */
+ { 9, 10, 5, 0, 0, }, /* 438 */
+ { 9, 7, 12, 0, 0, }, /* 439 */
+ { 12, 5, 12, 0, 0, }, /* 440 */
+ { 12, 6, 12, 0, 0, }, /* 441 */
+ { 33, 5, 12, 0, 35332, }, /* 442 */
+ { 33, 5, 12, 0, 3814, }, /* 443 */
+ { 33, 9, 12, 92, 1, }, /* 444 */
+ { 33, 5, 12, 92, -1, }, /* 445 */
+ { 33, 5, 12, 92, -58, }, /* 446 */
+ { 33, 9, 12, 0, -7615, }, /* 447 */
+ { 19, 5, 12, 0, 8, }, /* 448 */
+ { 19, 9, 12, 0, -8, }, /* 449 */
+ { 19, 5, 12, 0, 74, }, /* 450 */
+ { 19, 5, 12, 0, 86, }, /* 451 */
+ { 19, 5, 12, 0, 100, }, /* 452 */
+ { 19, 5, 12, 0, 128, }, /* 453 */
+ { 19, 5, 12, 0, 112, }, /* 454 */
+ { 19, 5, 12, 0, 126, }, /* 455 */
+ { 19, 8, 12, 0, -8, }, /* 456 */
+ { 19, 5, 12, 0, 9, }, /* 457 */
+ { 19, 9, 12, 0, -74, }, /* 458 */
+ { 19, 8, 12, 0, -9, }, /* 459 */
+ { 19, 5, 12, 21, -7173, }, /* 460 */
+ { 19, 9, 12, 0, -86, }, /* 461 */
+ { 19, 9, 12, 0, -100, }, /* 462 */
+ { 19, 9, 12, 0, -112, }, /* 463 */
+ { 19, 9, 12, 0, -128, }, /* 464 */
+ { 19, 9, 12, 0, -126, }, /* 465 */
+ { 27, 1, 3, 0, 0, }, /* 466 */
+ { 27, 1, 13, 0, 0, }, /* 467 */
+ { 9, 27, 2, 0, 0, }, /* 468 */
+ { 9, 28, 2, 0, 0, }, /* 469 */
+ { 9, 21, 14, 0, 0, }, /* 470 */
+ { 9, 2, 2, 0, 0, }, /* 471 */
+ { 9, 9, 12, 0, 0, }, /* 472 */
+ { 9, 5, 12, 0, 0, }, /* 473 */
+ { 19, 9, 12, 96, -7517, }, /* 474 */
+ { 33, 9, 12, 100, -8383, }, /* 475 */
+ { 33, 9, 12, 104, -8262, }, /* 476 */
+ { 33, 9, 12, 0, 28, }, /* 477 */
+ { 9, 5, 14, 0, 0, }, /* 478 */
+ { 33, 5, 12, 0, -28, }, /* 479 */
+ { 33, 14, 12, 0, 16, }, /* 480 */
+ { 33, 14, 12, 0, -16, }, /* 481 */
+ { 33, 14, 12, 0, 0, }, /* 482 */
+ { 9, 25, 14, 0, 0, }, /* 483 */
+ { 9, 26, 12, 0, 26, }, /* 484 */
+ { 9, 26, 14, 0, 26, }, /* 485 */
+ { 9, 26, 12, 0, -26, }, /* 486 */
+ { 4, 26, 12, 0, 0, }, /* 487 */
+ { 17, 9, 12, 0, 48, }, /* 488 */
+ { 17, 5, 12, 0, -48, }, /* 489 */
+ { 33, 9, 12, 0, -10743, }, /* 490 */
+ { 33, 9, 12, 0, -3814, }, /* 491 */
+ { 33, 9, 12, 0, -10727, }, /* 492 */
+ { 33, 5, 12, 0, -10795, }, /* 493 */
+ { 33, 5, 12, 0, -10792, }, /* 494 */
+ { 33, 9, 12, 0, -10780, }, /* 495 */
+ { 33, 9, 12, 0, -10749, }, /* 496 */
+ { 33, 9, 12, 0, -10783, }, /* 497 */
+ { 33, 9, 12, 0, -10782, }, /* 498 */
+ { 33, 9, 12, 0, -10815, }, /* 499 */
+ { 10, 5, 12, 0, 0, }, /* 500 */
+ { 10, 26, 12, 0, 0, }, /* 501 */
+ { 10, 12, 3, 0, 0, }, /* 502 */
+ { 10, 21, 12, 0, 0, }, /* 503 */
+ { 10, 15, 12, 0, 0, }, /* 504 */
+ { 16, 5, 12, 0, -7264, }, /* 505 */
+ { 58, 7, 12, 0, 0, }, /* 506 */
+ { 58, 6, 12, 0, 0, }, /* 507 */
+ { 58, 21, 12, 0, 0, }, /* 508 */
+ { 58, 12, 3, 0, 0, }, /* 509 */
+ { 22, 26, 12, 0, 0, }, /* 510 */
+ { 22, 6, 12, 0, 0, }, /* 511 */
+ { 22, 14, 12, 0, 0, }, /* 512 */
+ { 23, 10, 3, 0, 0, }, /* 513 */
+ { 9, 17, 14, 0, 0, }, /* 514 */
+ { 26, 7, 12, 0, 0, }, /* 515 */
+ { 26, 6, 12, 0, 0, }, /* 516 */
+ { 29, 7, 12, 0, 0, }, /* 517 */
+ { 29, 6, 12, 0, 0, }, /* 518 */
+ { 3, 7, 12, 0, 0, }, /* 519 */
+ { 23, 7, 12, 0, 0, }, /* 520 */
+ { 23, 26, 12, 0, 0, }, /* 521 */
+ { 29, 26, 12, 0, 0, }, /* 522 */
+ { 22, 7, 12, 0, 0, }, /* 523 */
+ { 60, 7, 12, 0, 0, }, /* 524 */
+ { 60, 6, 12, 0, 0, }, /* 525 */
+ { 60, 26, 12, 0, 0, }, /* 526 */
+ { 85, 7, 12, 0, 0, }, /* 527 */
+ { 85, 6, 12, 0, 0, }, /* 528 */
+ { 85, 21, 12, 0, 0, }, /* 529 */
+ { 76, 7, 12, 0, 0, }, /* 530 */
+ { 76, 6, 12, 0, 0, }, /* 531 */
+ { 76, 21, 12, 0, 0, }, /* 532 */
+ { 76, 13, 12, 0, 0, }, /* 533 */
+ { 12, 9, 12, 108, 1, }, /* 534 */
+ { 12, 5, 12, 108, -35267, }, /* 535 */
+ { 12, 7, 12, 0, 0, }, /* 536 */
+ { 12, 21, 12, 0, 0, }, /* 537 */
+ { 78, 7, 12, 0, 0, }, /* 538 */
+ { 78, 14, 12, 0, 0, }, /* 539 */
+ { 78, 12, 3, 0, 0, }, /* 540 */
+ { 78, 21, 12, 0, 0, }, /* 541 */
+ { 33, 9, 12, 0, -35332, }, /* 542 */
+ { 33, 9, 12, 0, -42280, }, /* 543 */
+ { 33, 9, 12, 0, -42308, }, /* 544 */
+ { 33, 9, 12, 0, -42319, }, /* 545 */
+ { 33, 9, 12, 0, -42315, }, /* 546 */
+ { 33, 9, 12, 0, -42305, }, /* 547 */
+ { 33, 9, 12, 0, -42258, }, /* 548 */
+ { 33, 9, 12, 0, -42282, }, /* 549 */
+ { 33, 9, 12, 0, -42261, }, /* 550 */
+ { 33, 9, 12, 0, 928, }, /* 551 */
+ { 48, 7, 12, 0, 0, }, /* 552 */
+ { 48, 12, 3, 0, 0, }, /* 553 */
+ { 48, 10, 5, 0, 0, }, /* 554 */
+ { 48, 26, 12, 0, 0, }, /* 555 */
+ { 64, 7, 12, 0, 0, }, /* 556 */
+ { 64, 21, 12, 0, 0, }, /* 557 */
+ { 74, 10, 5, 0, 0, }, /* 558 */
+ { 74, 7, 12, 0, 0, }, /* 559 */
+ { 74, 12, 3, 0, 0, }, /* 560 */
+ { 74, 21, 12, 0, 0, }, /* 561 */
+ { 74, 13, 12, 0, 0, }, /* 562 */
+ { 68, 13, 12, 0, 0, }, /* 563 */
+ { 68, 7, 12, 0, 0, }, /* 564 */
+ { 68, 12, 3, 0, 0, }, /* 565 */
+ { 68, 21, 12, 0, 0, }, /* 566 */
+ { 73, 7, 12, 0, 0, }, /* 567 */
+ { 73, 12, 3, 0, 0, }, /* 568 */
+ { 73, 10, 5, 0, 0, }, /* 569 */
+ { 73, 21, 12, 0, 0, }, /* 570 */
+ { 83, 12, 3, 0, 0, }, /* 571 */
+ { 83, 10, 5, 0, 0, }, /* 572 */
+ { 83, 7, 12, 0, 0, }, /* 573 */
+ { 83, 21, 12, 0, 0, }, /* 574 */
+ { 83, 13, 12, 0, 0, }, /* 575 */
+ { 38, 6, 12, 0, 0, }, /* 576 */
+ { 67, 7, 12, 0, 0, }, /* 577 */
+ { 67, 12, 3, 0, 0, }, /* 578 */
+ { 67, 10, 5, 0, 0, }, /* 579 */
+ { 67, 13, 12, 0, 0, }, /* 580 */
+ { 67, 21, 12, 0, 0, }, /* 581 */
+ { 91, 7, 12, 0, 0, }, /* 582 */
+ { 91, 12, 3, 0, 0, }, /* 583 */
+ { 91, 6, 12, 0, 0, }, /* 584 */
+ { 91, 21, 12, 0, 0, }, /* 585 */
+ { 86, 7, 12, 0, 0, }, /* 586 */
+ { 86, 10, 5, 0, 0, }, /* 587 */
+ { 86, 12, 3, 0, 0, }, /* 588 */
+ { 86, 21, 12, 0, 0, }, /* 589 */
+ { 86, 6, 12, 0, 0, }, /* 590 */
+ { 33, 5, 12, 0, -928, }, /* 591 */
+ { 8, 5, 12, 0, -38864, }, /* 592 */
+ { 86, 13, 12, 0, 0, }, /* 593 */
+ { 23, 7, 9, 0, 0, }, /* 594 */
+ { 23, 7, 10, 0, 0, }, /* 595 */
+ { 9, 4, 2, 0, 0, }, /* 596 */
+ { 9, 3, 12, 0, 0, }, /* 597 */
+ { 25, 25, 12, 0, 0, }, /* 598 */
+ { 0, 24, 12, 0, 0, }, /* 599 */
+ { 9, 6, 3, 0, 0, }, /* 600 */
+ { 35, 7, 12, 0, 0, }, /* 601 */
+ { 19, 14, 12, 0, 0, }, /* 602 */
+ { 19, 15, 12, 0, 0, }, /* 603 */
+ { 19, 26, 12, 0, 0, }, /* 604 */
+ { 70, 7, 12, 0, 0, }, /* 605 */
+ { 66, 7, 12, 0, 0, }, /* 606 */
+ { 41, 7, 12, 0, 0, }, /* 607 */
+ { 41, 15, 12, 0, 0, }, /* 608 */
+ { 18, 7, 12, 0, 0, }, /* 609 */
+ { 18, 14, 12, 0, 0, }, /* 610 */
+ { 117, 7, 12, 0, 0, }, /* 611 */
+ { 117, 12, 3, 0, 0, }, /* 612 */
+ { 59, 7, 12, 0, 0, }, /* 613 */
+ { 59, 21, 12, 0, 0, }, /* 614 */
+ { 42, 7, 12, 0, 0, }, /* 615 */
+ { 42, 21, 12, 0, 0, }, /* 616 */
+ { 42, 14, 12, 0, 0, }, /* 617 */
+ { 13, 9, 12, 0, 40, }, /* 618 */
+ { 13, 5, 12, 0, -40, }, /* 619 */
+ { 46, 7, 12, 0, 0, }, /* 620 */
+ { 44, 7, 12, 0, 0, }, /* 621 */
+ { 44, 13, 12, 0, 0, }, /* 622 */
+ { 135, 9, 12, 0, 40, }, /* 623 */
+ { 135, 5, 12, 0, -40, }, /* 624 */
+ { 105, 7, 12, 0, 0, }, /* 625 */
+ { 103, 7, 12, 0, 0, }, /* 626 */
+ { 103, 21, 12, 0, 0, }, /* 627 */
+ { 109, 7, 12, 0, 0, }, /* 628 */
+ { 11, 7, 12, 0, 0, }, /* 629 */
+ { 80, 7, 12, 0, 0, }, /* 630 */
+ { 80, 21, 12, 0, 0, }, /* 631 */
+ { 80, 15, 12, 0, 0, }, /* 632 */
+ { 119, 7, 12, 0, 0, }, /* 633 */
+ { 119, 26, 12, 0, 0, }, /* 634 */
+ { 119, 15, 12, 0, 0, }, /* 635 */
+ { 115, 7, 12, 0, 0, }, /* 636 */
+ { 115, 15, 12, 0, 0, }, /* 637 */
+ { 127, 7, 12, 0, 0, }, /* 638 */
+ { 127, 15, 12, 0, 0, }, /* 639 */
+ { 65, 7, 12, 0, 0, }, /* 640 */
+ { 65, 15, 12, 0, 0, }, /* 641 */
+ { 65, 21, 12, 0, 0, }, /* 642 */
+ { 71, 7, 12, 0, 0, }, /* 643 */
+ { 71, 21, 12, 0, 0, }, /* 644 */
+ { 97, 7, 12, 0, 0, }, /* 645 */
+ { 96, 7, 12, 0, 0, }, /* 646 */
+ { 96, 15, 12, 0, 0, }, /* 647 */
+ { 30, 7, 12, 0, 0, }, /* 648 */
+ { 30, 12, 3, 0, 0, }, /* 649 */
+ { 30, 15, 12, 0, 0, }, /* 650 */
+ { 30, 21, 12, 0, 0, }, /* 651 */
+ { 87, 7, 12, 0, 0, }, /* 652 */
+ { 87, 15, 12, 0, 0, }, /* 653 */
+ { 87, 21, 12, 0, 0, }, /* 654 */
+ { 116, 7, 12, 0, 0, }, /* 655 */
+ { 116, 15, 12, 0, 0, }, /* 656 */
+ { 111, 7, 12, 0, 0, }, /* 657 */
+ { 111, 26, 12, 0, 0, }, /* 658 */
+ { 111, 12, 3, 0, 0, }, /* 659 */
+ { 111, 15, 12, 0, 0, }, /* 660 */
+ { 111, 21, 12, 0, 0, }, /* 661 */
+ { 77, 7, 12, 0, 0, }, /* 662 */
+ { 77, 21, 12, 0, 0, }, /* 663 */
+ { 82, 7, 12, 0, 0, }, /* 664 */
+ { 82, 15, 12, 0, 0, }, /* 665 */
+ { 81, 7, 12, 0, 0, }, /* 666 */
+ { 81, 15, 12, 0, 0, }, /* 667 */
+ { 120, 7, 12, 0, 0, }, /* 668 */
+ { 120, 21, 12, 0, 0, }, /* 669 */
+ { 120, 15, 12, 0, 0, }, /* 670 */
+ { 88, 7, 12, 0, 0, }, /* 671 */
+ { 129, 9, 12, 0, 64, }, /* 672 */
+ { 129, 5, 12, 0, -64, }, /* 673 */
+ { 129, 15, 12, 0, 0, }, /* 674 */
+ { 143, 7, 12, 0, 0, }, /* 675 */
+ { 143, 12, 3, 0, 0, }, /* 676 */
+ { 143, 13, 12, 0, 0, }, /* 677 */
+ { 0, 15, 12, 0, 0, }, /* 678 */
+ { 146, 7, 12, 0, 0, }, /* 679 */
+ { 146, 15, 12, 0, 0, }, /* 680 */
+ { 147, 7, 12, 0, 0, }, /* 681 */
+ { 147, 12, 3, 0, 0, }, /* 682 */
+ { 147, 15, 12, 0, 0, }, /* 683 */
+ { 147, 21, 12, 0, 0, }, /* 684 */
+ { 93, 10, 5, 0, 0, }, /* 685 */
+ { 93, 12, 3, 0, 0, }, /* 686 */
+ { 93, 7, 12, 0, 0, }, /* 687 */
+ { 93, 21, 12, 0, 0, }, /* 688 */
+ { 93, 15, 12, 0, 0, }, /* 689 */
+ { 93, 13, 12, 0, 0, }, /* 690 */
+ { 84, 12, 3, 0, 0, }, /* 691 */
+ { 84, 10, 5, 0, 0, }, /* 692 */
+ { 84, 7, 12, 0, 0, }, /* 693 */
+ { 84, 21, 12, 0, 0, }, /* 694 */
+ { 84, 1, 4, 0, 0, }, /* 695 */
+ { 100, 7, 12, 0, 0, }, /* 696 */
+ { 100, 13, 12, 0, 0, }, /* 697 */
+ { 95, 12, 3, 0, 0, }, /* 698 */
+ { 95, 7, 12, 0, 0, }, /* 699 */
+ { 95, 10, 5, 0, 0, }, /* 700 */
+ { 95, 13, 12, 0, 0, }, /* 701 */
+ { 95, 21, 12, 0, 0, }, /* 702 */
+ { 110, 7, 12, 0, 0, }, /* 703 */
+ { 110, 12, 3, 0, 0, }, /* 704 */
+ { 110, 21, 12, 0, 0, }, /* 705 */
+ { 99, 12, 3, 0, 0, }, /* 706 */
+ { 99, 10, 5, 0, 0, }, /* 707 */
+ { 99, 7, 12, 0, 0, }, /* 708 */
+ { 99, 7, 4, 0, 0, }, /* 709 */
+ { 99, 21, 12, 0, 0, }, /* 710 */
+ { 99, 13, 12, 0, 0, }, /* 711 */
+ { 47, 15, 12, 0, 0, }, /* 712 */
+ { 107, 7, 12, 0, 0, }, /* 713 */
+ { 107, 10, 5, 0, 0, }, /* 714 */
+ { 107, 12, 3, 0, 0, }, /* 715 */
+ { 107, 21, 12, 0, 0, }, /* 716 */
+ { 128, 7, 12, 0, 0, }, /* 717 */
+ { 128, 21, 12, 0, 0, }, /* 718 */
+ { 108, 7, 12, 0, 0, }, /* 719 */
+ { 108, 12, 3, 0, 0, }, /* 720 */
+ { 108, 10, 5, 0, 0, }, /* 721 */
+ { 108, 13, 12, 0, 0, }, /* 722 */
+ { 106, 12, 3, 0, 0, }, /* 723 */
+ { 106, 10, 5, 0, 0, }, /* 724 */
+ { 106, 7, 12, 0, 0, }, /* 725 */
+ { 106, 10, 3, 0, 0, }, /* 726 */
+ { 134, 7, 12, 0, 0, }, /* 727 */
+ { 134, 10, 5, 0, 0, }, /* 728 */
+ { 134, 12, 3, 0, 0, }, /* 729 */
+ { 134, 21, 12, 0, 0, }, /* 730 */
+ { 134, 13, 12, 0, 0, }, /* 731 */
+ { 123, 7, 12, 0, 0, }, /* 732 */
+ { 123, 10, 3, 0, 0, }, /* 733 */
+ { 123, 10, 5, 0, 0, }, /* 734 */
+ { 123, 12, 3, 0, 0, }, /* 735 */
+ { 123, 21, 12, 0, 0, }, /* 736 */
+ { 123, 13, 12, 0, 0, }, /* 737 */
+ { 122, 7, 12, 0, 0, }, /* 738 */
+ { 122, 10, 3, 0, 0, }, /* 739 */
+ { 122, 10, 5, 0, 0, }, /* 740 */
+ { 122, 12, 3, 0, 0, }, /* 741 */
+ { 122, 21, 12, 0, 0, }, /* 742 */
+ { 113, 7, 12, 0, 0, }, /* 743 */
+ { 113, 10, 5, 0, 0, }, /* 744 */
+ { 113, 12, 3, 0, 0, }, /* 745 */
+ { 113, 21, 12, 0, 0, }, /* 746 */
+ { 113, 13, 12, 0, 0, }, /* 747 */
+ { 101, 7, 12, 0, 0, }, /* 748 */
+ { 101, 12, 3, 0, 0, }, /* 749 */
+ { 101, 10, 5, 0, 0, }, /* 750 */
+ { 101, 13, 12, 0, 0, }, /* 751 */
+ { 125, 7, 12, 0, 0, }, /* 752 */
+ { 125, 12, 3, 0, 0, }, /* 753 */
+ { 125, 10, 5, 0, 0, }, /* 754 */
+ { 125, 13, 12, 0, 0, }, /* 755 */
+ { 125, 15, 12, 0, 0, }, /* 756 */
+ { 125, 21, 12, 0, 0, }, /* 757 */
+ { 125, 26, 12, 0, 0, }, /* 758 */
+ { 141, 7, 12, 0, 0, }, /* 759 */
+ { 141, 10, 5, 0, 0, }, /* 760 */
+ { 141, 12, 3, 0, 0, }, /* 761 */
+ { 141, 21, 12, 0, 0, }, /* 762 */
+ { 124, 9, 12, 0, 32, }, /* 763 */
+ { 124, 5, 12, 0, -32, }, /* 764 */
+ { 124, 13, 12, 0, 0, }, /* 765 */
+ { 124, 15, 12, 0, 0, }, /* 766 */
+ { 124, 7, 12, 0, 0, }, /* 767 */
+ { 140, 7, 12, 0, 0, }, /* 768 */
+ { 140, 12, 3, 0, 0, }, /* 769 */
+ { 140, 10, 5, 0, 0, }, /* 770 */
+ { 140, 7, 4, 0, 0, }, /* 771 */
+ { 140, 21, 12, 0, 0, }, /* 772 */
+ { 139, 7, 12, 0, 0, }, /* 773 */
+ { 139, 12, 3, 0, 0, }, /* 774 */
+ { 139, 10, 5, 0, 0, }, /* 775 */
+ { 139, 7, 4, 0, 0, }, /* 776 */
+ { 139, 21, 12, 0, 0, }, /* 777 */
+ { 121, 7, 12, 0, 0, }, /* 778 */
+ { 132, 7, 12, 0, 0, }, /* 779 */
+ { 132, 10, 5, 0, 0, }, /* 780 */
+ { 132, 12, 3, 0, 0, }, /* 781 */
+ { 132, 21, 12, 0, 0, }, /* 782 */
+ { 132, 13, 12, 0, 0, }, /* 783 */
+ { 132, 15, 12, 0, 0, }, /* 784 */
+ { 133, 21, 12, 0, 0, }, /* 785 */
+ { 133, 7, 12, 0, 0, }, /* 786 */
+ { 133, 12, 3, 0, 0, }, /* 787 */
+ { 133, 10, 5, 0, 0, }, /* 788 */
+ { 137, 7, 12, 0, 0, }, /* 789 */
+ { 137, 12, 3, 0, 0, }, /* 790 */
+ { 137, 7, 4, 0, 0, }, /* 791 */
+ { 137, 13, 12, 0, 0, }, /* 792 */
+ { 142, 7, 12, 0, 0, }, /* 793 */
+ { 142, 10, 5, 0, 0, }, /* 794 */
+ { 142, 12, 3, 0, 0, }, /* 795 */
+ { 142, 13, 12, 0, 0, }, /* 796 */
+ { 144, 7, 12, 0, 0, }, /* 797 */
+ { 144, 12, 3, 0, 0, }, /* 798 */
+ { 144, 10, 5, 0, 0, }, /* 799 */
+ { 144, 21, 12, 0, 0, }, /* 800 */
+ { 62, 7, 12, 0, 0, }, /* 801 */
+ { 62, 14, 12, 0, 0, }, /* 802 */
+ { 62, 21, 12, 0, 0, }, /* 803 */
+ { 79, 7, 12, 0, 0, }, /* 804 */
+ { 126, 7, 12, 0, 0, }, /* 805 */
+ { 114, 7, 12, 0, 0, }, /* 806 */
+ { 114, 13, 12, 0, 0, }, /* 807 */
+ { 114, 21, 12, 0, 0, }, /* 808 */
+ { 102, 7, 12, 0, 0, }, /* 809 */
+ { 102, 12, 3, 0, 0, }, /* 810 */
+ { 102, 21, 12, 0, 0, }, /* 811 */
+ { 118, 7, 12, 0, 0, }, /* 812 */
+ { 118, 12, 3, 0, 0, }, /* 813 */
+ { 118, 21, 12, 0, 0, }, /* 814 */
+ { 118, 26, 12, 0, 0, }, /* 815 */
+ { 118, 6, 12, 0, 0, }, /* 816 */
+ { 118, 13, 12, 0, 0, }, /* 817 */
+ { 118, 15, 12, 0, 0, }, /* 818 */
+ { 145, 9, 12, 0, 32, }, /* 819 */
+ { 145, 5, 12, 0, -32, }, /* 820 */
+ { 145, 15, 12, 0, 0, }, /* 821 */
+ { 145, 21, 12, 0, 0, }, /* 822 */
+ { 98, 7, 12, 0, 0, }, /* 823 */
+ { 98, 10, 5, 0, 0, }, /* 824 */
+ { 98, 12, 3, 0, 0, }, /* 825 */
+ { 98, 6, 12, 0, 0, }, /* 826 */
+ { 136, 6, 12, 0, 0, }, /* 827 */
+ { 138, 6, 12, 0, 0, }, /* 828 */
+ { 136, 7, 12, 0, 0, }, /* 829 */
+ { 138, 7, 12, 0, 0, }, /* 830 */
+ { 104, 7, 12, 0, 0, }, /* 831 */
+ { 104, 26, 12, 0, 0, }, /* 832 */
+ { 104, 12, 3, 0, 0, }, /* 833 */
+ { 104, 21, 12, 0, 0, }, /* 834 */
+ { 9, 10, 3, 0, 0, }, /* 835 */
+ { 19, 12, 3, 0, 0, }, /* 836 */
+ { 130, 26, 12, 0, 0, }, /* 837 */
+ { 130, 12, 3, 0, 0, }, /* 838 */
+ { 130, 21, 12, 0, 0, }, /* 839 */
+ { 17, 12, 3, 0, 0, }, /* 840 */
+ { 112, 7, 12, 0, 0, }, /* 841 */
+ { 112, 15, 12, 0, 0, }, /* 842 */
+ { 112, 12, 3, 0, 0, }, /* 843 */
+ { 131, 9, 12, 0, 34, }, /* 844 */
+ { 131, 5, 12, 0, -34, }, /* 845 */
+ { 131, 12, 3, 0, 0, }, /* 846 */
+ { 131, 13, 12, 0, 0, }, /* 847 */
+ { 131, 21, 12, 0, 0, }, /* 848 */
+ { 9, 2, 14, 0, 0, }, /* 849 */
+ { 9, 26, 11, 0, 0, }, /* 850 */
+ { 26, 26, 12, 0, 0, }, /* 851 */
+ { 9, 24, 3, 0, 0, }, /* 852 */
+ { 9, 1, 3, 0, 0, }, /* 853 */
+};
+
+const uint16_t PRIV(ucd_stage1)[] = { /* 17408 bytes */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* U+0000 */
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* U+0800 */
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 42, 43, 44, 45, /* U+1000 */
+ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, /* U+1800 */
+ 62, 63, 64, 65, 66, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, /* U+2000 */
+ 77, 77, 78, 79, 66, 66, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, /* U+2800 */
+ 90, 91, 92, 93, 94, 95, 96, 71, 97, 97, 97, 97, 97, 97, 97, 97, /* U+3000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+3800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+4000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 97, 97, 97, 97, /* U+4800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+5000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+5800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+6000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+6800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+7000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+7800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+8000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+8800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+9000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 99, /* U+9800 */
+100,101,101,101,101,101,101,101,101,102,103,103,104,105,106,107, /* U+A000 */
+108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,116, /* U+A800 */
+117,118,119,120,121,122,116,117,118,119,120,121,122,116,117,118, /* U+B000 */
+119,120,121,122,116,117,118,119,120,121,122,116,117,118,119,120, /* U+B800 */
+121,122,116,117,118,119,120,121,122,116,117,118,119,120,121,122, /* U+C000 */
+116,117,118,119,120,121,122,116,117,118,119,120,121,122,116,117, /* U+C800 */
+118,119,120,121,122,116,117,118,119,120,121,122,116,117,118,123, /* U+D000 */
+124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, /* U+D800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+E000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+E800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F000 */
+125,125, 97, 97,126,127,128,129,130,130,131,132,133,134,135,136, /* U+F800 */
+137,138,139,140,141,142,143,144,145,146,147,141,148,148,149,141, /* U+10000 */
+150,151,152,153,154,155,156,157,158,159,160,141,161,141,162,141, /* U+10800 */
+163,164,165,166,167,168,169,141,170,171,141,172,173,174,175,141, /* U+11000 */
+176,177,141,141,178,179,141,141,180,181,182,183,141,184,141,141, /* U+11800 */
+185,185,185,185,185,185,185,186,187,185,188,141,141,141,141,141, /* U+12000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+12800 */
+189,189,189,189,189,189,189,189,190,141,141,141,141,141,141,141, /* U+13000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+13800 */
+141,141,141,141,141,141,141,141,191,191,191,191,192,141,141,141, /* U+14000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+14800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+15000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+15800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+16000 */
+193,193,193,193,194,195,196,197,141,141,141,141,198,199,200,201, /* U+16800 */
+202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, /* U+17000 */
+202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, /* U+17800 */
+202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,203, /* U+18000 */
+202,202,202,202,202,204,141,141,141,141,141,141,141,141,141,141, /* U+18800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+19000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+19800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1A800 */
+205,206,207,208,208,209,141,141,141,141,141,141,141,141,141,141, /* U+1B000 */
+141,141,141,141,141,141,141,141,210,211,141,141,141,141,141,141, /* U+1B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1C800 */
+ 71,212,213,214,215,216,217,141,218,219,220,221,222,223,224,225, /* U+1D000 */
+226,226,226,226,227,228,141,141,141,141,141,141,141,141,141,141, /* U+1D800 */
+229,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+1E000 */
+230,231,232,141,141,141,141,141,233,234,141,141,235,236,141,141, /* U+1E800 */
+237,238,239,240,241,242,243,244,243,243,245,243,246,247,248,249, /* U+1F000 */
+250,251,252,253,254,242,242,242,242,242,242,242,242,242,242,255, /* U+1F800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+20000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+20800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+21000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+21800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+22000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+22800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+23000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+23800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+24000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+24800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+25000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+25800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+26000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+26800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+27000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+27800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+28000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+28800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+29000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+29800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,256, 97, 97, /* U+2A000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+2A800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,257, 97, /* U+2B000 */
+258, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+2B800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+2C000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,259, 97, 97, /* U+2C800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+2D000 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+2D800 */
+ 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, /* U+2E000 */
+ 97, 97, 97, 97, 97, 97, 97,260,141,141,141,141,141,141,141,141, /* U+2E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+2F000 */
+ 97, 97, 97, 97,261,141,141,141,141,141,141,141,141,141,141,141, /* U+2F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+30000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+30800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+31000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+31800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+32000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+32800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+33000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+33800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+34000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+34800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+35000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+35800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+36000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+36800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+37000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+37800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+38000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+38800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+39000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+39800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+3F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+40000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+40800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+41000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+41800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+42000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+42800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+43000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+43800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+44000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+44800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+45000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+45800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+46000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+46800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+47000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+47800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+48000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+48800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+49000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+49800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+4F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+50000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+50800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+51000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+51800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+52000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+52800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+53000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+53800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+54000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+54800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+55000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+55800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+56000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+56800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+57000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+57800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+58000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+58800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+59000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+59800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+5F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+60000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+60800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+61000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+61800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+62000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+62800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+63000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+63800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+64000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+64800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+65000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+65800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+66000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+66800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+67000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+67800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+68000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+68800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+69000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+69800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+6F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+70000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+70800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+71000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+71800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+72000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+72800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+73000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+73800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+74000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+74800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+75000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+75800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+76000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+76800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+77000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+77800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+78000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+78800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+79000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+79800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+7F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+80000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+80800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+81000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+81800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+82000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+82800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+83000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+83800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+84000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+84800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+85000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+85800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+86000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+86800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+87000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+87800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+88000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+88800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+89000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+89800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+8F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+90000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+90800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+91000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+91800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+92000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+92800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+93000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+93800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+94000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+94800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+95000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+95800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+96000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+96800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+97000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+97800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+98000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+98800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+99000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+99800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9A000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9A800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9B000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9B800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9C000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9C800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9D000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9D800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9E000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9E800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9F000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+9F800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+A9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+AF800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+B9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+BF800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+C9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+CF800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D0000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+D9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DD000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DD800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+DF800 */
+262,263,264,265,263,263,263,263,263,263,263,263,263,263,263,263, /* U+E0000 */
+263,263,263,263,263,263,263,263,263,263,263,263,263,263,263,263, /* U+E0800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E1000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E1800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E2000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E2800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E3000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E3800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E4000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E4800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E5000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E5800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E6000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E6800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E7000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E7800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E8000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E8800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E9000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+E9800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EA000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EA800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EB000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EB800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EC000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EC800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+ED000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+ED800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EE000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EE800 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EF000 */
+141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, /* U+EF800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F0000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F0800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F1000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F1800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F2000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F2800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F3000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F3800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F4000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F4800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F5000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F5800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F6000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F6800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F7000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F7800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F8000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F8800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F9000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+F9800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FA000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FA800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FB000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FB800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FC000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FC800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FD000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FD800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FE000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FE800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+FF000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,266, /* U+FF800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+100000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+100800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+101000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+101800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+102000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+102800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+103000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+103800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+104000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+104800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+105000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+105800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+106000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+106800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+107000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+107800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+108000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+108800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+109000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+109800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10A000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10A800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10B000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10B800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10C000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10C800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10D000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10D800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10E000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10E800 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, /* U+10F000 */
+125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,266, /* U+10F800 */
+};
+
+const uint16_t PRIV(ucd_stage2)[] = { /* 68352 bytes, block = 128 */
+/* block 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 4, 4, 4, 5, 4, 4, 4, 6, 7, 4, 8, 4, 9, 4, 4,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 8, 8, 8, 4,
+ 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 11, 11, 11, 11,
+ 11, 11, 11, 13, 11, 11, 11, 11, 11, 11, 11, 6, 4, 7, 14, 15,
+ 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 16, 16, 16,
+ 16, 16, 16, 18, 16, 16, 16, 16, 16, 16, 16, 6, 8, 7, 8, 0,
+
+/* block 1 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 4, 5, 5, 5, 5, 19, 4, 14, 20, 21, 22, 8, 23, 20, 14,
+ 19, 8, 24, 24, 14, 25, 4, 4, 14, 24, 21, 26, 24, 24, 24, 4,
+ 11, 11, 11, 11, 11, 27, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 8, 11, 11, 11, 11, 11, 11, 11, 28,
+ 16, 16, 16, 16, 16, 29, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 8, 16, 16, 16, 16, 16, 16, 16, 30,
+
+/* block 2 */
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 33, 34, 31, 32, 31, 32, 31, 32, 34, 31, 32, 31, 32, 31, 32, 31,
+ 32, 31, 32, 31, 32, 31, 32, 31, 32, 34, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 35, 31, 32, 31, 32, 31, 32, 36,
+
+/* block 3 */
+ 37, 38, 31, 32, 31, 32, 39, 31, 32, 40, 40, 31, 32, 34, 41, 42,
+ 43, 31, 32, 40, 44, 45, 46, 47, 31, 32, 48, 34, 46, 49, 50, 51,
+ 31, 32, 31, 32, 31, 32, 52, 31, 32, 52, 34, 34, 31, 32, 52, 31,
+ 32, 53, 53, 31, 32, 31, 32, 54, 31, 32, 34, 21, 31, 32, 34, 55,
+ 21, 21, 21, 21, 56, 57, 58, 59, 60, 61, 62, 63, 64, 31, 32, 31,
+ 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 65, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 34, 66, 67, 68, 31, 32, 69, 70, 31, 32, 31, 32, 31, 32, 31, 32,
+
+/* block 4 */
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 71, 34, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 34, 34, 34, 34, 34, 34, 72, 31, 32, 73, 74, 75,
+ 75, 31, 32, 76, 77, 78, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 79, 80, 81, 82, 83, 34, 84, 84, 34, 85, 34, 86, 87, 34, 34, 34,
+ 84, 88, 34, 89, 34, 90, 91, 34, 92, 93, 91, 94, 95, 34, 34, 93,
+ 34, 96, 97, 34, 34, 98, 34, 34, 34, 34, 34, 34, 34, 99, 34, 34,
+
+/* block 5 */
+100, 34, 34,100, 34, 34, 34,101,100,102,103,103,104, 34, 34, 34,
+ 34, 34,105, 34, 21, 34, 34, 34, 34, 34, 34, 34, 34,106,107, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+108,108,108,108,108,108,108,108,108,109,109,109,109,109,109,109,
+109,109, 14, 14, 14, 14,109,109,109,109,109,109,109,109,109,109,
+109,109, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+108,108,108,108,108, 14, 14, 14, 14, 14,110,110,109, 14,109, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+
+/* block 6 */
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,112,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+113,114,113,114,109,115,113,114,116,116,117,118,118,118, 4,119,
+
+/* block 7 */
+116,116,116,116,115, 14,120, 4,121,121,121,116,122,116,123,123,
+124,125,126,125,125,127,125,125,128,129,130,125,131,125,125,125,
+132,133,116,134,125,125,135,125,125,136,125,125,137,138,138,138,
+124,139,140,139,139,141,139,139,142,143,144,139,145,139,139,139,
+146,147,148,149,139,139,150,139,139,151,139,139,152,153,153,154,
+155,156,157,157,157,158,159,160,113,114,113,114,113,114,113,114,
+113,114,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+163,164,165,166,167,168,169,113,114,170,113,114,124,171,171,171,
+
+/* block 8 */
+172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+173,173,174,173,175,173,173,173,173,173,173,173,173,173,176,173,
+173,177,178,173,173,173,173,173,173,173,179,173,173,173,173,173,
+180,180,181,180,182,180,180,180,180,180,180,180,180,180,183,180,
+180,184,185,180,180,180,180,180,180,180,186,180,180,180,180,180,
+187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,
+188,189,190,191,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+
+/* block 9 */
+188,189,192,193,193,111,111,193,194,194,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+195,188,189,188,189,188,189,188,189,188,189,188,189,188,189,196,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+
+/* block 10 */
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+116,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
+197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,
+197,197,197,197,197,197,197,116,116,198,199,199,199,199,199,199,
+200,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
+201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,
+
+/* block 11 */
+201,201,201,201,201,201,201,200,200, 4,202,116,116,203,203,204,
+116,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
+205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,
+205,205,205,205,205,205,205,205,205,205,205,205,205,205,206,205,
+207,205,205,207,205,205,207,205,116,116,116,116,116,116,116,116,
+208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,
+208,208,208,208,208,208,208,208,208,208,208,116,116,116,116,208,
+208,208,208,207,207,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 12 */
+209,209,209,209,209,210,211,211,211,212,212,213, 4,212,214,214,
+215,215,215,215,215,215,215,215,215,215,215, 4,216,116,212, 4,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+109,217,217,217,217,217,217,217,217,217,217,111,111,111,111,111,
+111,111,111,111,111,111,215,215,215,215,215,215,215,215,215,215,
+218,218,218,218,218,218,218,218,218,218,212,212,212,212,217,217,
+111,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+
+/* block 13 */
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,212,217,215,215,215,215,215,215,215,210,214,215,
+215,215,215,215,215,219,219,215,215,214,215,215,215,215,217,217,
+218,218,218,218,218,218,218,218,218,218,217,217,217,214,214,217,
+
+/* block 14 */
+220,220,220,220,220,220,220,220,220,220,220,220,220,220,116,221,
+222,223,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,
+223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,
+223,223,223,223,223,223,223,223,223,223,223,116,116,222,222,222,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+
+/* block 15 */
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,
+224,224,224,224,224,224,225,225,225,225,225,225,225,225,225,225,
+225,224,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+226,226,226,226,226,226,226,226,226,226,227,227,227,227,227,227,
+227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,
+227,227,227,227,227,227,227,227,227,227,227,228,228,228,228,228,
+228,228,228,228,229,229,230,231,231,231,229,116,116,228,232,232,
+
+/* block 16 */
+233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,
+233,233,233,233,233,233,234,234,234,234,235,234,234,234,234,234,
+234,234,234,234,235,234,234,234,235,234,234,234,234,234,116,116,
+236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,116,
+237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,
+237,237,237,237,237,237,237,237,237,238,238,238,116,116,239,116,
+222,222,222,222,222,222,222,222,222,222,222,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 17 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,116,217,217,217,217,217,217,217,217,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,215,215,215,215,215,215,215,215,215,215,215,215,215,
+215,215,210,215,215,215,215,215,215,215,215,215,215,215,215,215,
+215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,
+
+/* block 18 */
+240,240,240,241,242,242,242,242,242,242,242,242,242,242,242,242,
+242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,
+242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,
+242,242,242,242,242,242,242,242,242,242,240,241,240,242,241,241,
+241,240,240,240,240,240,240,240,240,241,241,241,241,240,241,241,
+242,111,111,240,240,240,240,240,242,242,242,242,242,242,242,242,
+242,242,240,240, 4, 4,243,243,243,243,243,243,243,243,243,243,
+244,245,242,242,242,242,242,242,242,242,242,242,242,242,242,242,
+
+/* block 19 */
+246,247,248,248,116,246,246,246,246,246,246,246,246,116,116,246,
+246,116,116,246,246,246,246,246,246,246,246,246,246,246,246,246,
+246,246,246,246,246,246,246,246,246,116,246,246,246,246,246,246,
+246,116,246,116,116,116,246,246,246,246,116,116,247,246,249,248,
+248,247,247,247,247,116,116,248,248,116,116,248,248,247,246,116,
+116,116,116,116,116,116,116,249,116,116,116,116,246,246,116,246,
+246,246,247,247,116,116,250,250,250,250,250,250,250,250,250,250,
+246,246,251,251,252,252,252,252,252,252,253,251,246,254,247,116,
+
+/* block 20 */
+116,255,255,256,116,257,257,257,257,257,257,116,116,116,116,257,
+257,116,116,257,257,257,257,257,257,257,257,257,257,257,257,257,
+257,257,257,257,257,257,257,257,257,116,257,257,257,257,257,257,
+257,116,257,257,116,257,257,116,257,257,116,116,255,116,256,256,
+256,255,255,116,116,116,116,255,255,116,116,255,255,255,116,116,
+116,255,116,116,116,116,116,116,116,257,257,257,257,116,257,116,
+116,116,116,116,116,116,258,258,258,258,258,258,258,258,258,258,
+255,255,257,257,257,255,259,116,116,116,116,116,116,116,116,116,
+
+/* block 21 */
+116,260,260,261,116,262,262,262,262,262,262,262,262,262,116,262,
+262,262,116,262,262,262,262,262,262,262,262,262,262,262,262,262,
+262,262,262,262,262,262,262,262,262,116,262,262,262,262,262,262,
+262,116,262,262,116,262,262,262,262,262,116,116,260,262,261,261,
+261,260,260,260,260,260,116,260,260,261,116,261,261,260,116,116,
+262,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+262,262,260,260,116,116,263,263,263,263,263,263,263,263,263,263,
+264,265,116,116,116,116,116,116,116,262,260,260,260,260,260,260,
+
+/* block 22 */
+116,266,267,267,116,268,268,268,268,268,268,268,268,116,116,268,
+268,116,116,268,268,268,268,268,268,268,268,268,268,268,268,268,
+268,268,268,268,268,268,268,268,268,116,268,268,268,268,268,268,
+268,116,268,268,116,268,268,268,268,268,116,116,266,268,269,266,
+267,266,266,266,266,116,116,267,267,116,116,267,267,266,116,116,
+116,116,116,116,116,116,266,269,116,116,116,116,268,268,116,268,
+268,268,266,266,116,116,270,270,270,270,270,270,270,270,270,270,
+271,268,272,272,272,272,272,272,116,116,116,116,116,116,116,116,
+
+/* block 23 */
+116,116,273,274,116,274,274,274,274,274,274,116,116,116,274,274,
+274,116,274,274,274,274,116,116,116,274,274,116,274,116,274,274,
+116,116,116,274,274,116,116,116,274,274,274,116,116,116,274,274,
+274,274,274,274,274,274,274,274,274,274,116,116,116,116,275,276,
+273,276,276,116,116,116,276,276,276,116,276,276,276,273,116,116,
+274,116,116,116,116,116,116,275,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,277,277,277,277,277,277,277,277,277,277,
+278,278,278,279,279,279,279,279,279,280,279,116,116,116,116,116,
+
+/* block 24 */
+281,282,282,282,281,283,283,283,283,283,283,283,283,116,283,283,
+283,116,283,283,283,283,283,283,283,283,283,283,283,283,283,283,
+283,283,283,283,283,283,283,283,283,116,283,283,283,283,283,283,
+283,283,283,283,283,283,283,283,283,283,116,116,116,283,281,281,
+281,282,282,282,282,116,281,281,281,116,281,281,281,281,116,116,
+116,116,116,116,116,281,281,116,283,283,283,116,116,116,116,116,
+283,283,281,281,116,116,284,284,284,284,284,284,284,284,284,284,
+116,116,116,116,116,116,116,116,285,285,285,285,285,285,285,286,
+
+/* block 25 */
+287,288,289,289,290,287,287,287,287,287,287,287,287,116,287,287,
+287,116,287,287,287,287,287,287,287,287,287,287,287,287,287,287,
+287,287,287,287,287,287,287,287,287,116,287,287,287,287,287,287,
+287,287,287,287,116,287,287,287,287,287,116,116,288,287,289,288,
+289,289,291,289,289,116,288,289,289,116,289,289,288,288,116,116,
+116,116,116,116,116,291,291,116,116,116,116,116,116,116,287,116,
+287,287,288,288,116,116,292,292,292,292,292,292,292,292,292,292,
+116,287,287,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 26 */
+293,293,294,294,116,295,295,295,295,295,295,295,295,116,295,295,
+295,116,295,295,295,295,295,295,295,295,295,295,295,295,295,295,
+295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,295,
+295,295,295,295,295,295,295,295,295,295,295,293,293,295,296,294,
+294,293,293,293,293,116,294,294,294,116,294,294,294,293,297,298,
+116,116,116,116,295,295,295,296,299,299,299,299,299,299,299,295,
+295,295,293,293,116,116,300,300,300,300,300,300,300,300,300,300,
+299,299,299,299,299,299,299,299,299,298,295,295,295,295,295,295,
+
+/* block 27 */
+116,116,301,301,116,302,302,302,302,302,302,302,302,302,302,302,
+302,302,302,302,302,302,302,116,116,116,302,302,302,302,302,302,
+302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,302,
+302,302,116,302,302,302,302,302,302,302,302,302,116,302,116,116,
+302,302,302,302,302,302,302,116,116,116,303,116,116,116,116,304,
+301,301,303,303,303,116,303,116,301,301,301,301,301,301,301,304,
+116,116,116,116,116,116,305,305,305,305,305,305,305,305,305,305,
+116,116,301,301,306,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 28 */
+116,307,307,307,307,307,307,307,307,307,307,307,307,307,307,307,
+307,307,307,307,307,307,307,307,307,307,307,307,307,307,307,307,
+307,307,307,307,307,307,307,307,307,307,307,307,307,307,307,307,
+307,308,307,309,308,308,308,308,308,308,308,116,116,116,116, 5,
+307,307,307,307,307,307,310,308,308,308,308,308,308,308,308,311,
+312,312,312,312,312,312,312,312,312,312,311,311,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 29 */
+116,313,313,116,313,116,116,313,313,116,313,116,116,313,116,116,
+116,116,116,116,313,313,313,313,116,313,313,313,313,313,313,313,
+116,313,313,313,116,313,116,313,116,116,313,313,116,313,313,313,
+313,314,313,315,314,314,314,314,314,314,116,314,314,313,116,116,
+313,313,313,313,313,116,316,116,314,314,314,314,314,314,116,116,
+317,317,317,317,317,317,317,317,317,317,116,116,313,313,313,313,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 30 */
+318,319,319,319,320,320,320,320,320,320,320,320,320,320,320,320,
+320,320,320,319,320,319,319,319,321,321,319,319,319,319,319,319,
+322,322,322,322,322,322,322,322,322,322,323,323,323,323,323,323,
+323,323,323,323,319,321,319,321,319,321,324,325,324,325,326,326,
+318,318,318,318,318,318,318,318,116,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,318,
+318,318,318,318,318,318,318,318,318,318,318,318,318,116,116,116,
+116,321,321,321,321,321,321,321,321,321,321,321,321,321,321,326,
+
+/* block 31 */
+321,321,321,321,321,320,321,321,318,318,318,318,318,321,321,321,
+321,321,321,321,321,321,321,321,116,321,321,321,321,321,321,321,
+321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,321,
+321,321,321,321,321,321,321,321,321,321,321,321,321,116,319,319,
+319,319,319,319,319,319,321,319,319,319,319,319,319,116,319,319,
+320,320,320,320,320, 19, 19, 19, 19,320,320,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 32 */
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+327,327,327,327,327,327,327,327,327,327,327,328,328,329,329,329,
+329,330,329,329,329,329,329,329,328,329,329,330,330,329,329,327,
+331,331,331,331,331,331,331,331,331,331,332,332,332,332,332,332,
+327,327,327,327,327,327,330,330,329,329,327,327,327,327,329,329,
+329,327,328,328,328,327,327,328,328,328,328,328,328,328,327,327,
+327,329,329,329,329,327,327,327,327,327,327,327,327,327,327,327,
+
+/* block 33 */
+327,327,329,328,330,329,329,328,328,328,328,328,328,329,327,328,
+331,331,331,331,331,331,331,331,331,331,328,328,328,329,333,333,
+334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,
+334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,334,
+334,334,334,334,334,334,116,334,116,116,116,116,116,334,116,116,
+335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,
+335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,335,
+335,335,335,335,335,335,335,335,335,335,335, 4,336,335,335,335,
+
+/* block 34 */
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
+338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
+
+/* block 35 */
+338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
+338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
+338,338,338,338,338,338,338,338,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+
+/* block 36 */
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,116,340,340,340,340,116,116,
+340,340,340,340,340,340,340,116,340,116,340,340,340,340,116,116,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+
+/* block 37 */
+340,340,340,340,340,340,340,340,340,116,340,340,340,340,116,116,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,116,340,340,340,340,116,116,340,340,340,340,340,340,340,116,
+340,116,340,340,340,340,116,116,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,116,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+
+/* block 38 */
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,116,340,340,340,340,116,116,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,340,340,340,340,116,116,341,341,341,
+342,342,342,342,342,342,342,342,342,343,343,343,343,343,343,343,
+343,343,343,343,343,343,343,343,343,343,343,343,343,116,116,116,
+
+/* block 39 */
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+344,344,344,344,344,344,344,344,344,344,116,116,116,116,116,116,
+345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,
+345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,
+345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,
+345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,
+345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,345,
+346,346,346,346,346,346,116,116,347,347,347,347,347,347,116,116,
+
+/* block 40 */
+348,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+
+/* block 41 */
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+
+/* block 42 */
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,350,350,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+
+/* block 43 */
+351,352,352,352,352,352,352,352,352,352,352,352,352,352,352,352,
+352,352,352,352,352,352,352,352,352,352,352,353,354,116,116,116,
+355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
+355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
+355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
+355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,355,
+355,355,355,355,355,355,355,355,355,355,355, 4, 4, 4,356,356,
+356,355,355,355,355,355,355,355,355,116,116,116,116,116,116,116,
+
+/* block 44 */
+357,357,357,357,357,357,357,357,357,357,357,357,357,116,357,357,
+357,357,358,358,358,116,116,116,116,116,116,116,116,116,116,116,
+359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,359,
+359,359,360,360,360, 4, 4,116,116,116,116,116,116,116,116,116,
+361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,361,
+361,361,362,362,116,116,116,116,116,116,116,116,116,116,116,116,
+363,363,363,363,363,363,363,363,363,363,363,363,363,116,363,363,
+363,116,364,364,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 45 */
+365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,
+365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,
+365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,365,
+365,365,365,365,366,366,367,366,366,366,366,366,366,366,367,367,
+367,367,367,367,367,367,366,367,367,366,366,366,366,366,366,366,
+366,366,366,366,368,368,368,369,368,368,368,370,365,366,116,116,
+371,371,371,371,371,371,371,371,371,371,116,116,116,116,116,116,
+372,372,372,372,372,372,372,372,372,372,116,116,116,116,116,116,
+
+/* block 46 */
+373,373, 4, 4,373, 4,374,373,373,373,373,375,375,375,376,116,
+377,377,377,377,377,377,377,377,377,377,116,116,116,116,116,116,
+378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,
+378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,
+378,378,378,379,378,378,378,378,378,378,378,378,378,378,378,378,
+378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,
+378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,
+378,378,378,378,378,378,378,378,378,116,116,116,116,116,116,116,
+
+/* block 47 */
+378,378,378,378,378,375,375,378,378,378,378,378,378,378,378,378,
+378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,378,
+378,378,378,378,378,378,378,378,378,375,378,116,116,116,116,116,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,349,
+349,349,349,349,349,349,116,116,116,116,116,116,116,116,116,116,
+
+/* block 48 */
+380,380,380,380,380,380,380,380,380,380,380,380,380,380,380,380,
+380,380,380,380,380,380,380,380,380,380,380,380,380,380,380,116,
+381,381,381,382,382,382,382,381,381,382,382,382,116,116,116,116,
+382,382,381,382,382,382,382,382,382,381,381,381,116,116,116,116,
+383,116,116,116,384,384,385,385,385,385,385,385,385,385,385,385,
+386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,386,
+386,386,386,386,386,386,386,386,386,386,386,386,386,386,116,116,
+386,386,386,386,386,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 49 */
+387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,
+387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,
+387,387,387,387,387,387,387,387,387,387,387,387,116,116,116,116,
+387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,387,
+387,387,387,387,387,387,387,387,387,387,116,116,116,116,116,116,
+388,388,388,388,388,388,388,388,388,388,389,116,116,116,390,390,
+391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,
+391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,391,
+
+/* block 50 */
+392,392,392,392,392,392,392,392,392,392,392,392,392,392,392,392,
+392,392,392,392,392,392,392,393,393,394,394,393,116,116,395,395,
+396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,
+396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,
+396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,396,
+396,396,396,396,396,397,398,397,398,398,398,398,398,398,398,116,
+398,399,398,399,399,398,398,398,398,398,398,398,398,397,397,397,
+397,397,397,398,398,398,398,398,398,398,398,398,398,116,116,398,
+
+/* block 51 */
+400,400,400,400,400,400,400,400,400,400,116,116,116,116,116,116,
+400,400,400,400,400,400,400,400,400,400,116,116,116,116,116,116,
+401,401,401,401,401,401,401,402,401,401,401,401,401,401,116,116,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,403,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 52 */
+404,404,404,404,405,406,406,406,406,406,406,406,406,406,406,406,
+406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,
+406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,406,
+406,406,406,406,404,405,404,404,404,404,404,405,404,405,405,405,
+405,405,404,405,405,406,406,406,406,406,406,406,116,116,116,116,
+407,407,407,407,407,407,407,407,407,407,408,408,408,408,408,408,
+408,409,409,409,409,409,409,409,409,409,409,404,404,404,404,404,
+404,404,404,404,409,409,409,409,409,409,409,409,409,116,116,116,
+
+/* block 53 */
+410,410,411,412,412,412,412,412,412,412,412,412,412,412,412,412,
+412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,412,
+412,411,410,410,410,410,411,411,410,410,411,410,410,410,412,412,
+413,413,413,413,413,413,413,413,413,413,412,412,412,412,412,412,
+414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,
+414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,414,
+414,414,414,414,414,414,415,416,415,415,416,416,416,415,416,415,
+415,415,416,416,116,116,116,116,116,116,116,116,417,417,417,417,
+
+/* block 54 */
+418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
+418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,418,
+418,418,418,418,419,419,419,419,419,419,419,419,420,420,420,420,
+420,420,420,420,419,419,420,420,116,116,116,421,421,421,421,421,
+422,422,422,422,422,422,422,422,422,422,116,116,116,418,418,418,
+423,423,423,423,423,423,423,423,423,423,424,424,424,424,424,424,
+424,424,424,424,424,424,424,424,424,424,424,424,424,424,424,424,
+424,424,424,424,424,424,424,424,425,425,425,425,425,425,426,426,
+
+/* block 55 */
+427,428,429,430,431,432,433,434,435,116,116,116,116,116,116,116,
+436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
+436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,436,
+436,436,436,436,436,436,436,436,436,436,436,116,116,436,436,436,
+437,437,437,437,437,437,437,437,116,116,116,116,116,116,116,116,
+111,111,111, 4,111,111,111,111,111,111,111,111,111,111,111,111,
+111,438,111,111,111,111,111,111,111,439,439,439,439,111,439,439,
+439,439,438,438,111,439,439,438,111,111,116,116,116,116,116,116,
+
+/* block 56 */
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34,124,124,124,124,124,440,108,108,108,108,
+108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+108,108,108,108,108,108,108,108,108,108,108,108,108,117,117,117,
+117,117,108,108,108,108,117,117,117,117,117, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34,441,442, 34, 34, 34,443, 34, 34,
+
+/* block 57 */
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,108,108,108,108,108,
+108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
+108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,117,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,116,111,111,111,111,111,
+
+/* block 58 */
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+444,445, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+
+/* block 59 */
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 34, 34, 34, 34, 34,446, 34, 34,447, 34,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+
+/* block 60 */
+448,448,448,448,448,448,448,448,449,449,449,449,449,449,449,449,
+448,448,448,448,448,448,116,116,449,449,449,449,449,449,116,116,
+448,448,448,448,448,448,448,448,449,449,449,449,449,449,449,449,
+448,448,448,448,448,448,448,448,449,449,449,449,449,449,449,449,
+448,448,448,448,448,448,116,116,449,449,449,449,449,449,116,116,
+124,448,124,448,124,448,124,448,116,449,116,449,116,449,116,449,
+448,448,448,448,448,448,448,448,449,449,449,449,449,449,449,449,
+450,450,451,451,451,451,452,452,453,453,454,454,455,455,116,116,
+
+/* block 61 */
+448,448,448,448,448,448,448,448,456,456,456,456,456,456,456,456,
+448,448,448,448,448,448,448,448,456,456,456,456,456,456,456,456,
+448,448,448,448,448,448,448,448,456,456,456,456,456,456,456,456,
+448,448,124,457,124,116,124,124,449,449,458,458,459,115,460,115,
+115,115,124,457,124,116,124,124,461,461,461,461,459,115,115,115,
+448,448,124,124,116,116,124,124,449,449,462,462,116,115,115,115,
+448,448,124,124,124,165,124,124,449,449,463,463,170,115,115,115,
+116,116,124,457,124,116,124,124,464,464,465,465,459,115,115,116,
+
+/* block 62 */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 23,466,467, 23, 23,
+ 9, 9, 9, 9, 9, 9, 4, 4, 22, 26, 6, 22, 22, 26, 6, 22,
+ 4, 4, 4, 4, 4, 4, 4, 4,468,469, 23, 23, 23, 23, 23, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 22, 26, 4,470, 4, 4, 15,
+ 15, 4, 4, 4, 8, 6, 7, 4, 4,470, 4, 4, 4, 4, 4, 4,
+ 4, 4, 8, 4, 15, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3,
+ 23, 23, 23, 23, 23,471, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 24,108,116,116, 24, 24, 24, 24, 24, 24, 8, 8, 8, 6, 7,108,
+
+/* block 63 */
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 6, 7,116,
+108,108,108,108,108,108,108,108,108,108,108,108,108,116,116,116,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+111,111,111,111,111,111,111,111,111,111,111,111,111,403,403,403,
+403,111,403,403,403,111,111,111,111,111,111,111,111,111,111,111,
+111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 64 */
+ 19, 19,472, 19, 19, 19, 19,472, 19, 19,473,472,472,472,473,473,
+472,472,472,473, 19,472, 19, 19, 8,472,472,472,472,472, 19, 19,
+ 19, 19, 20, 19,472, 19,474, 19,472, 19,475,476,472,472, 19,473,
+472,472,477,472,473,439,439,439,439,478, 19, 19,473,473,472,472,
+ 8, 8, 8, 8, 8,472,473,473,473,473, 19, 8, 19, 19,479, 19,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,
+481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,481,
+
+/* block 65 */
+482,482,482, 31, 32,482,482,482,482, 24, 19, 19,116,116,116,116,
+ 8, 8, 8, 8,483, 20, 20, 20, 20, 20, 8, 8, 19, 19, 19, 19,
+ 8, 19, 19, 8, 19, 19, 8, 19, 19, 20, 20, 19, 19, 19, 8, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8,
+ 19, 19, 8, 19, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+/* block 66 */
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+/* block 67 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 6, 7, 6, 7, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 19, 19, 19, 19,
+ 8, 8, 19, 19, 19, 19, 19, 19, 20, 6, 7, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 19, 19, 19,
+
+/* block 68 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 20, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8, 8,
+ 8, 8, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 19, 19, 19, 19, 20, 20, 20, 19, 19, 19, 19, 19,
+
+/* block 69 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+
+/* block 70 */
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19,484,484,484,484,484,484,484,484,484,484,
+484,484,485,484,484,484,484,484,484,484,484,484,484,484,484,484,
+486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,486,
+486,486,486,486,486,486,486,486,486,486, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+
+/* block 71 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 72 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 20, 8, 19, 19, 19, 19, 19, 19, 19, 19,
+ 20, 8, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 8, 8, 8,483,483,483,483, 8,
+
+/* block 73 */
+ 20, 20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,483,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 74 */
+ 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 75 */
+ 20, 20, 20, 20, 20, 20, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 19, 20, 19, 20, 19, 19, 19, 19, 19, 19, 20, 19, 19,
+ 19, 20, 19, 19, 19, 19, 19, 19, 20, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 20, 19, 19, 20, 19, 19, 19, 19, 20, 19, 20, 19,
+ 19, 19, 19, 20, 20, 20, 19, 20, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 20, 20, 20, 20, 20, 6, 7, 6, 7, 6, 7, 6, 7,
+ 6, 7, 6, 7, 6, 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+
+/* block 76 */
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 19, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20,
+ 8, 8, 8, 8, 8, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+/* block 77 */
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,487,
+
+/* block 78 */
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8,483,483, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+
+/* block 79 */
+ 8, 8, 8, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6,
+ 7, 6, 7, 6, 7, 6, 7, 6, 7, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 6, 7, 6, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 7, 8, 8,
+
+/* block 80 */
+ 19, 19, 19, 19, 19, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 19, 19, 8, 8, 8, 8, 8, 8, 19, 19, 19,
+ 20, 19, 19, 19, 19, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,116,116, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 81 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19,116,116, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,116, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,116,
+
+/* block 82 */
+488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,
+488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,
+488,488,488,488,488,488,488,488,488,488,488,488,488,488,488,116,
+489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,
+489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,
+489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,116,
+ 31, 32,490,491,492,493,494, 31, 32, 31, 32, 31, 32,495,496,497,
+498, 34, 31, 32, 34, 31, 32, 34, 34, 34, 34, 34,108,108,499,499,
+
+/* block 83 */
+161,162,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+161,162,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+161,162,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+161,162,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+161,162,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+161,162,161,162,161,162,161,162,161,162,161,162,161,162,161,162,
+161,162,161,162,500,501,501,501,501,501,501,161,162,161,162,502,
+502,502,161,162,116,116,116,116,116,503,503,503,503,504,503,503,
+
+/* block 84 */
+505,505,505,505,505,505,505,505,505,505,505,505,505,505,505,505,
+505,505,505,505,505,505,505,505,505,505,505,505,505,505,505,505,
+505,505,505,505,505,505,116,505,116,116,116,116,116,505,116,116,
+506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,
+506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,
+506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,506,
+506,506,506,506,506,506,506,506,116,116,116,116,116,116,116,507,
+508,116,116,116,116,116,116,116,116,116,116,116,116,116,116,509,
+
+/* block 85 */
+340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,340,
+340,340,340,340,340,340,340,116,116,116,116,116,116,116,116,116,
+340,340,340,340,340,340,340,116,340,340,340,340,340,340,340,116,
+340,340,340,340,340,340,340,116,340,340,340,340,340,340,340,116,
+340,340,340,340,340,340,340,116,340,340,340,340,340,340,340,116,
+340,340,340,340,340,340,340,116,340,340,340,340,340,340,340,116,
+193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
+193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,
+
+/* block 86 */
+ 4, 4, 22, 26, 22, 26, 4, 4, 4, 22, 26, 4, 22, 26, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 9, 4, 4, 9, 4, 22, 26, 4, 4,
+ 22, 26, 6, 7, 6, 7, 6, 7, 6, 7, 4, 4, 4, 4, 4,109,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 9, 9, 4, 4, 4, 4,
+ 9, 4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 87 */
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,116,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 88 */
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+
+/* block 89 */
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,510,
+510,510,510,510,510,510,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,116,116,116,116,
+
+/* block 90 */
+ 3, 4, 4, 4, 19,511,439,512, 6, 7, 6, 7, 6, 7, 6, 7,
+ 6, 7, 19, 19, 6, 7, 6, 7, 6, 7, 6, 7, 9, 6, 7, 7,
+ 19,512,512,512,512,512,512,512,512,512,111,111,111,111,513,513,
+514,109,109,109,109,109, 19, 19,512,512,512,511,439,470, 19, 19,
+116,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+
+/* block 91 */
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,116,116,111,111, 14, 14,516,516,515,
+ 9,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+517,517,517,517,517,517,517,517,517,517,517, 4,109,518,518,517,
+
+/* block 92 */
+116,116,116,116,116,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+116,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,
+
+/* block 93 */
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,116,
+ 19, 19, 24, 24, 24, 24, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,519,
+519,519,519,519,519,519,519,519,519,519,519,116,116,116,116,116,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,116,116,116,116,116,116,116,116,116,116,116,116,
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+
+/* block 94 */
+521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,
+521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,116,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 24, 24, 24, 24, 24, 24, 24, 24,
+ 19, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,
+521,521,521,521,521,521,521,521,521,521,521,521,521,521,521, 19,
+
+/* block 95 */
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 20, 19, 20, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,116,
+
+/* block 96 */
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,522,
+522,522,522,522,522,522,522,522, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 97 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+
+/* block 98 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,116,116,116,116,116,116,116,116,116,116,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 99 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 100 */
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,525,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+
+/* block 101 */
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,524,
+
+/* block 102 */
+524,524,524,524,524,524,524,524,524,524,524,524,524,116,116,116,
+526,526,526,526,526,526,526,526,526,526,526,526,526,526,526,526,
+526,526,526,526,526,526,526,526,526,526,526,526,526,526,526,526,
+526,526,526,526,526,526,526,526,526,526,526,526,526,526,526,526,
+526,526,526,526,526,526,526,116,116,116,116,116,116,116,116,116,
+527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,
+527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,
+527,527,527,527,527,527,527,527,528,528,528,528,528,528,529,529,
+
+/* block 103 */
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+
+/* block 104 */
+530,530,530,530,530,530,530,530,530,530,530,530,531,532,532,532,
+530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,530,
+533,533,533,533,533,533,533,533,533,533,530,530,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+188,189,188,189,188,189,188,189,188,189,534,535,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,536,193,
+194,194,194,537,193,193,193,193,193,193,193,193,193,193,537,441,
+
+/* block 105 */
+188,189,188,189,188,189,188,189,188,189,188,189,188,189,188,189,
+188,189,188,189,188,189,188,189,188,189,188,189,441,441,193,193,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,539,539,539,539,539,539,539,539,539,539,
+540,540,541,541,541,541,541,541,116,116,116,116,116,116,116,116,
+
+/* block 106 */
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14,109,109,109,109,109,109,109,109,109,
+ 14, 14, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 34, 34, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+108, 34, 34, 34, 34, 34, 34, 34, 34, 31, 32, 31, 32,542, 31, 32,
+
+/* block 107 */
+ 31, 32, 31, 32, 31, 32, 31, 32,109, 14, 14, 31, 32,543, 34, 21,
+ 31, 32, 31, 32, 34, 34, 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,
+ 31, 32, 31, 32, 31, 32, 31, 32, 31, 32,544,545,546,547,544, 34,
+548,549,550,551, 31, 32, 31, 32, 31, 32,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116, 21,108,108, 34, 21, 21, 21, 21, 21,
+
+/* block 108 */
+552,552,553,552,552,552,553,552,552,552,552,553,552,552,552,552,
+552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,552,
+552,552,552,554,554,553,553,554,555,555,555,555,116,116,116,116,
+ 24, 24, 24, 24, 24, 24, 19, 19, 5, 19,116,116,116,116,116,116,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,556,
+556,556,556,556,557,557,557,557,116,116,116,116,116,116,116,116,
+
+/* block 109 */
+558,558,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,559,
+559,559,559,559,558,558,558,558,558,558,558,558,558,558,558,558,
+558,558,558,558,560,560,116,116,116,116,116,116,116,116,561,561,
+562,562,562,562,562,562,562,562,562,562,116,116,116,116,116,116,
+240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,
+240,240,242,242,242,242,242,242,244,244,244,242,244,242,242,240,
+
+/* block 110 */
+563,563,563,563,563,563,563,563,563,563,564,564,564,564,564,564,
+564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,564,
+564,564,564,564,564,564,565,565,565,565,565,565,565,565, 4,566,
+567,567,567,567,567,567,567,567,567,567,567,567,567,567,567,567,
+567,567,567,567,567,567,567,568,568,568,568,568,568,568,568,568,
+568,568,569,569,116,116,116,116,116,116,116,116,116,116,116,570,
+337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,337,
+337,337,337,337,337,337,337,337,337,337,337,337,337,116,116,116,
+
+/* block 111 */
+571,571,571,572,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,573,
+573,573,573,571,572,572,571,571,571,571,572,572,571,572,572,572,
+572,574,574,574,574,574,574,574,574,574,574,574,574,574,116,109,
+575,575,575,575,575,575,575,575,575,575,116,116,116,116,574,574,
+327,327,327,327,327,329,576,327,327,327,327,327,327,327,327,327,
+331,331,331,331,331,331,331,331,331,331,327,327,327,327,327,116,
+
+/* block 112 */
+577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,
+577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,577,
+577,577,577,577,577,577,577,577,577,578,578,578,578,578,578,579,
+579,578,578,579,579,578,578,116,116,116,116,116,116,116,116,116,
+577,577,577,578,577,577,577,577,577,577,577,577,578,579,116,116,
+580,580,580,580,580,580,580,580,580,580,116,116,581,581,581,581,
+327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,327,
+576,327,327,327,327,327,327,333,333,333,327,328,329,328,327,327,
+
+/* block 113 */
+582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
+582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
+582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,582,
+583,582,583,583,583,582,582,583,583,582,582,582,582,582,583,583,
+582,583,582,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,582,582,584,585,585,
+586,586,586,586,586,586,586,586,586,586,586,587,588,588,587,587,
+589,589,586,590,590,587,588,116,116,116,116,116,116,116,116,116,
+
+/* block 114 */
+116,340,340,340,340,340,340,116,116,340,340,340,340,340,340,116,
+116,340,340,340,340,340,340,116,116,116,116,116,116,116,116,116,
+340,340,340,340,340,340,340,116,340,340,340,340,340,340,340,116,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34,591, 34, 34, 34, 34, 34, 34, 34, 14,108,108,108,108,
+ 34, 34, 34, 34, 34,124,116,116,116,116,116,116,116,116,116,116,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+
+/* block 115 */
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,592,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,586,
+586,586,586,587,587,588,587,587,588,587,587,589,587,588,116,116,
+593,593,593,593,593,593,593,593,593,593,116,116,116,116,116,116,
+
+/* block 116 */
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+
+/* block 117 */
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+
+/* block 118 */
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+
+/* block 119 */
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+
+/* block 120 */
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+
+/* block 121 */
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+
+/* block 122 */
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+594,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,594,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,594,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+
+/* block 123 */
+595,595,595,595,595,595,595,595,594,595,595,595,595,595,595,595,
+595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,595,
+595,595,595,595,116,116,116,116,116,116,116,116,116,116,116,116,
+338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,338,
+338,338,338,338,338,338,338,116,116,116,116,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,
+339,339,339,339,339,339,339,339,339,339,339,339,116,116,116,116,
+
+/* block 124 */
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,596,
+
+/* block 125 */
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+
+/* block 126 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,116,116,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+
+/* block 127 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 128 */
+ 34, 34, 34, 34, 34, 34, 34,116,116,116,116,116,116,116,116,116,
+116,116,116,200,200,200,200,200,116,116,116,116,116,208,205,208,
+208,208,208,208,208,208,208,208,208,598,208,208,208,208,208,208,
+208,208,208,208,208,208,208,116,208,208,208,208,208,116,208,116,
+208,208,116,208,208,116,208,208,208,208,208,208,208,208,208,208,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+
+/* block 129 */
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,599,599,599,599,599,599,599,599,599,599,599,599,599,599,
+599,599,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+
+/* block 130 */
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+
+/* block 131 */
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217, 7, 6,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+
+/* block 132 */
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+116,116,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+217,217,217,217,217,217,217,217,217,217,217,217,213,214,116,116,
+
+/* block 133 */
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+ 4, 4, 4, 4, 4, 4, 4, 6, 7, 4,116,116,116,116,116,116,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,193,193,
+ 4, 9, 9, 15, 15, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6,
+ 7, 6, 7, 6, 7, 4, 4, 6, 7, 4, 4, 4, 4, 15, 15, 15,
+ 4, 4, 4,116, 4, 4, 4, 4, 9, 6, 7, 6, 7, 6, 7, 4,
+ 4, 4, 8, 9, 8, 8, 8,116, 4, 5, 4, 4,116,116,116,116,
+217,217,217,217,217,116,217,217,217,217,217,217,217,217,217,217,
+
+/* block 134 */
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,116,116, 23,
+
+/* block 135 */
+116, 4, 4, 4, 5, 4, 4, 4, 6, 7, 4, 8, 4, 9, 4, 4,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 8, 8, 8, 4,
+ 4, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6, 4, 7, 14, 15,
+ 14, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 6, 8, 7, 8, 6,
+ 7, 4, 6, 7, 4, 4,517,517,517,517,517,517,517,517,517,517,
+109,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+
+/* block 136 */
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,
+517,517,517,517,517,517,517,517,517,517,517,517,517,517,600,600,
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,
+520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,116,
+116,116,520,520,520,520,520,520,116,116,520,520,520,520,520,520,
+116,116,520,520,520,520,520,520,116,116,520,520,520,116,116,116,
+ 5, 5, 8, 14, 19, 5, 5,116, 19, 8, 8, 8, 8, 19, 19,116,
+471,471,471,471,471,471,471,471,471, 23, 23, 23, 19, 19,116,116,
+
+/* block 137 */
+601,601,601,601,601,601,601,601,601,601,601,601,116,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,116,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,116,601,601,116,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,116,116,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 138 */
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,601,
+601,601,601,601,601,601,601,601,601,601,601,116,116,116,116,116,
+
+/* block 139 */
+ 4, 4, 4,116,116,116,116, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24,116,116,116, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,
+602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,
+602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,602,
+602,602,602,602,602,603,603,603,603,604,604,604,604,604,604,604,
+
+/* block 140 */
+604,604,604,604,604,604,604,604,604,604,603,603,604,604,604,116,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,116,116,116,116,
+604,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,111,116,116,
+
+/* block 141 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 142 */
+605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,605,
+605,605,605,605,605,605,605,605,605,605,605,605,605,116,116,116,
+606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,
+606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,
+606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,606,
+606,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+111, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,116,116,116,116,
+
+/* block 143 */
+607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,
+607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,607,
+608,608,608,608,116,116,116,116,116,116,116,116,116,607,607,607,
+609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,609,
+609,610,609,609,609,609,609,609,609,609,610,116,116,116,116,116,
+611,611,611,611,611,611,611,611,611,611,611,611,611,611,611,611,
+611,611,611,611,611,611,611,611,611,611,611,611,611,611,611,611,
+611,611,611,611,611,611,612,612,612,612,612,116,116,116,116,116,
+
+/* block 144 */
+613,613,613,613,613,613,613,613,613,613,613,613,613,613,613,613,
+613,613,613,613,613,613,613,613,613,613,613,613,613,613,116,614,
+615,615,615,615,615,615,615,615,615,615,615,615,615,615,615,615,
+615,615,615,615,615,615,615,615,615,615,615,615,615,615,615,615,
+615,615,615,615,116,116,116,116,615,615,615,615,615,615,615,615,
+616,617,617,617,617,617,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 145 */
+618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,
+618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,618,
+618,618,618,618,618,618,618,618,619,619,619,619,619,619,619,619,
+619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,
+619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,619,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,620,
+
+/* block 146 */
+621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,621,
+621,621,621,621,621,621,621,621,621,621,621,621,621,621,116,116,
+622,622,622,622,622,622,622,622,622,622,116,116,116,116,116,116,
+623,623,623,623,623,623,623,623,623,623,623,623,623,623,623,623,
+623,623,623,623,623,623,623,623,623,623,623,623,623,623,623,623,
+623,623,623,623,116,116,116,116,624,624,624,624,624,624,624,624,
+624,624,624,624,624,624,624,624,624,624,624,624,624,624,624,624,
+624,624,624,624,624,624,624,624,624,624,624,624,116,116,116,116,
+
+/* block 147 */
+625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,
+625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,625,
+625,625,625,625,625,625,625,625,116,116,116,116,116,116,116,116,
+626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,
+626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,
+626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,626,
+626,626,626,626,116,116,116,116,116,116,116,116,116,116,116,627,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 148 */
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+
+/* block 149 */
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,628,116,116,116,116,116,116,116,116,116,
+628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,628,
+628,628,628,628,628,628,116,116,116,116,116,116,116,116,116,116,
+628,628,628,628,628,628,628,628,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 150 */
+629,629,629,629,629,629,116,116,629,116,629,629,629,629,629,629,
+629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,
+629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,629,
+629,629,629,629,629,629,116,629,629,116,116,116,629,116,116,629,
+630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,630,
+630,630,630,630,630,630,116,631,632,632,632,632,632,632,632,632,
+633,633,633,633,633,633,633,633,633,633,633,633,633,633,633,633,
+633,633,633,633,633,633,633,634,634,635,635,635,635,635,635,635,
+
+/* block 151 */
+636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,
+636,636,636,636,636,636,636,636,636,636,636,636,636,636,636,116,
+116,116,116,116,116,116,116,637,637,637,637,637,637,637,637,637,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+638,638,638,638,638,638,638,638,638,638,638,638,638,638,638,638,
+638,638,638,116,638,638,116,116,116,116,116,639,639,639,639,639,
+
+/* block 152 */
+640,640,640,640,640,640,640,640,640,640,640,640,640,640,640,640,
+640,640,640,640,640,640,641,641,641,641,641,641,116,116,116,642,
+643,643,643,643,643,643,643,643,643,643,643,643,643,643,643,643,
+643,643,643,643,643,643,643,643,643,643,116,116,116,116,116,644,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 153 */
+645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,
+645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,645,
+646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,646,
+646,646,646,646,646,646,646,646,116,116,116,116,647,647,646,646,
+647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,
+116,116,647,647,647,647,647,647,647,647,647,647,647,647,647,647,
+647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,
+647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,647,
+
+/* block 154 */
+648,649,649,649,116,649,649,116,116,116,116,116,649,649,649,649,
+648,648,648,648,116,648,648,648,116,648,648,648,648,648,648,648,
+648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,648,
+648,648,648,648,648,648,116,116,649,649,649,116,116,116,116,649,
+650,650,650,650,650,650,650,650,650,116,116,116,116,116,116,116,
+651,651,651,651,651,651,651,651,651,116,116,116,116,116,116,116,
+652,652,652,652,652,652,652,652,652,652,652,652,652,652,652,652,
+652,652,652,652,652,652,652,652,652,652,652,652,652,653,653,654,
+
+/* block 155 */
+655,655,655,655,655,655,655,655,655,655,655,655,655,655,655,655,
+655,655,655,655,655,655,655,655,655,655,655,655,655,656,656,656,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+657,657,657,657,657,657,657,657,658,657,657,657,657,657,657,657,
+657,657,657,657,657,657,657,657,657,657,657,657,657,657,657,657,
+657,657,657,657,657,659,659,116,116,116,116,660,660,660,660,660,
+661,661,661,661,661,661,661,116,116,116,116,116,116,116,116,116,
+
+/* block 156 */
+662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
+662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
+662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,662,
+662,662,662,662,662,662,116,116,116,663,663,663,663,663,663,663,
+664,664,664,664,664,664,664,664,664,664,664,664,664,664,664,664,
+664,664,664,664,664,664,116,116,665,665,665,665,665,665,665,665,
+666,666,666,666,666,666,666,666,666,666,666,666,666,666,666,666,
+666,666,666,116,116,116,116,116,667,667,667,667,667,667,667,667,
+
+/* block 157 */
+668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,668,
+668,668,116,116,116,116,116,116,116,669,669,669,669,116,116,116,
+116,116,116,116,116,116,116,116,116,670,670,670,670,670,670,670,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 158 */
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,671,
+671,671,671,671,671,671,671,671,671,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 159 */
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,672,
+672,672,672,116,116,116,116,116,116,116,116,116,116,116,116,116,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,673,
+673,673,673,116,116,116,116,116,116,116,674,674,674,674,674,674,
+
+/* block 160 */
+675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
+675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,675,
+675,675,675,675,676,676,676,676,116,116,116,116,116,116,116,116,
+677,677,677,677,677,677,677,677,677,677,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 161 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,
+678,678,678,678,678,678,678,678,678,678,678,678,678,678,678,116,
+
+/* block 162 */
+679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,679,
+679,679,679,679,679,679,679,679,679,679,679,679,679,680,680,680,
+680,680,680,680,680,680,680,679,116,116,116,116,116,116,116,116,
+681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,681,
+681,681,681,681,681,681,682,682,682,682,682,682,682,682,682,682,
+682,683,683,683,683,684,684,684,684,684,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 163 */
+685,686,685,687,687,687,687,687,687,687,687,687,687,687,687,687,
+687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
+687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,687,
+687,687,687,687,687,687,687,687,686,686,686,686,686,686,686,686,
+686,686,686,686,686,686,686,688,688,688,688,688,688,688,116,116,
+116,116,689,689,689,689,689,689,689,689,689,689,689,689,689,689,
+689,689,689,689,689,689,690,690,690,690,690,690,690,690,690,690,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,686,
+
+/* block 164 */
+691,691,692,693,693,693,693,693,693,693,693,693,693,693,693,693,
+693,693,693,693,693,693,693,693,693,693,693,693,693,693,693,693,
+693,693,693,693,693,693,693,693,693,693,693,693,693,693,693,693,
+692,692,692,691,691,691,691,692,692,691,691,694,694,695,694,694,
+694,694,116,116,116,116,116,116,116,116,116,116,116,695,116,116,
+696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,696,
+696,696,696,696,696,696,696,696,696,116,116,116,116,116,116,116,
+697,697,697,697,697,697,697,697,697,697,116,116,116,116,116,116,
+
+/* block 165 */
+698,698,698,699,699,699,699,699,699,699,699,699,699,699,699,699,
+699,699,699,699,699,699,699,699,699,699,699,699,699,699,699,699,
+699,699,699,699,699,699,699,698,698,698,698,698,700,698,698,698,
+698,698,698,698,698,116,701,701,701,701,701,701,701,701,701,701,
+702,702,702,702,699,700,700,116,116,116,116,116,116,116,116,116,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,703,
+703,703,703,704,705,705,703,116,116,116,116,116,116,116,116,116,
+
+/* block 166 */
+706,706,707,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,708,
+708,708,708,707,707,707,706,706,706,706,706,706,706,706,706,707,
+707,708,709,709,708,710,710,710,710,706,706,706,706,710,116,116,
+711,711,711,711,711,711,711,711,711,711,708,710,708,710,710,710,
+116,712,712,712,712,712,712,712,712,712,712,712,712,712,712,712,
+712,712,712,712,712,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 167 */
+713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,713,
+713,713,116,713,713,713,713,713,713,713,713,713,713,713,713,713,
+713,713,713,713,713,713,713,713,713,713,713,713,714,714,714,715,
+715,715,714,714,715,714,715,715,716,716,716,716,716,716,715,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 168 */
+717,717,717,717,717,717,717,116,717,116,717,717,717,717,116,717,
+717,717,717,717,717,717,717,717,717,717,717,717,717,717,116,717,
+717,717,717,717,717,717,717,717,717,718,116,116,116,116,116,116,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,
+719,719,719,719,719,719,719,719,719,719,719,719,719,719,719,720,
+721,721,721,720,720,720,720,720,720,720,720,116,116,116,116,116,
+722,722,722,722,722,722,722,722,722,722,116,116,116,116,116,116,
+
+/* block 169 */
+723,723,724,724,116,725,725,725,725,725,725,725,725,116,116,725,
+725,116,116,725,725,725,725,725,725,725,725,725,725,725,725,725,
+725,725,725,725,725,725,725,725,725,116,725,725,725,725,725,725,
+725,116,725,725,116,725,725,725,725,725,116,111,723,725,726,724,
+723,724,724,724,724,116,116,724,724,116,116,724,724,724,116,116,
+725,116,116,116,116,116,116,726,116,116,116,116,116,725,725,725,
+725,725,724,724,116,116,723,723,723,723,723,723,723,116,116,116,
+723,723,723,723,723,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 170 */
+727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,
+727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,
+727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,727,
+727,727,727,727,727,728,728,728,729,729,729,729,729,729,729,729,
+728,728,729,729,729,728,729,727,727,727,727,730,730,730,730,730,
+731,731,731,731,731,731,731,731,731,731,116,730,116,730,729,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 171 */
+732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,
+732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,
+732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,732,
+733,734,734,735,735,735,735,735,735,734,735,734,734,733,734,735,
+735,734,735,735,732,732,736,732,116,116,116,116,116,116,116,116,
+737,737,737,737,737,737,737,737,737,737,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 172 */
+738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,
+738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,
+738,738,738,738,738,738,738,738,738,738,738,738,738,738,738,739,
+740,740,741,741,741,741,116,116,740,740,740,740,741,741,740,741,
+741,742,742,742,742,742,742,742,742,742,742,742,742,742,742,742,
+742,742,742,742,742,742,742,742,738,738,738,738,741,741,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 173 */
+743,743,743,743,743,743,743,743,743,743,743,743,743,743,743,743,
+743,743,743,743,743,743,743,743,743,743,743,743,743,743,743,743,
+743,743,743,743,743,743,743,743,743,743,743,743,743,743,743,743,
+744,744,744,745,745,745,745,745,745,745,745,744,744,745,744,745,
+745,746,746,746,743,116,116,116,116,116,116,116,116,116,116,116,
+747,747,747,747,747,747,747,747,747,747,116,116,116,116,116,116,
+373,373,373,373,373,373,373,373,373,373,373,373,373,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 174 */
+748,748,748,748,748,748,748,748,748,748,748,748,748,748,748,748,
+748,748,748,748,748,748,748,748,748,748,748,748,748,748,748,748,
+748,748,748,748,748,748,748,748,748,748,748,749,750,749,750,750,
+749,749,749,749,749,749,750,749,116,116,116,116,116,116,116,116,
+751,751,751,751,751,751,751,751,751,751,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 175 */
+752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,752,
+752,752,752,752,752,752,752,752,752,752,752,116,116,753,753,753,
+754,754,753,753,753,753,754,753,753,753,753,753,116,116,116,116,
+755,755,755,755,755,755,755,755,755,755,756,756,757,757,757,758,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 176 */
+759,759,759,759,759,759,759,759,759,759,759,759,759,759,759,759,
+759,759,759,759,759,759,759,759,759,759,759,759,759,759,759,759,
+759,759,759,759,759,759,759,759,759,759,759,759,760,760,760,761,
+761,761,761,761,761,761,761,761,760,761,761,762,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 177 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
+763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,763,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,764,
+765,765,765,765,765,765,765,765,765,765,766,766,766,766,766,766,
+766,766,766,116,116,116,116,116,116,116,116,116,116,116,116,767,
+
+/* block 178 */
+768,769,769,769,769,769,769,769,769,769,769,768,768,768,768,768,
+768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,
+768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,768,
+768,768,768,769,769,769,769,769,769,770,771,769,769,769,769,772,
+772,772,772,772,772,772,772,769,116,116,116,116,116,116,116,116,
+773,774,774,774,774,774,774,775,775,774,774,774,773,773,773,773,
+773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,
+773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,773,
+
+/* block 179 */
+773,773,773,773,116,116,776,776,776,776,774,774,774,774,774,774,
+774,774,774,774,774,774,774,775,774,774,777,777,777,773,777,777,
+777,777,777,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+778,778,778,778,778,778,778,778,778,778,778,778,778,778,778,778,
+778,778,778,778,778,778,778,778,778,778,778,778,778,778,778,778,
+778,778,778,778,778,778,778,778,778,778,778,778,778,778,778,778,
+778,778,778,778,778,778,778,778,778,116,116,116,116,116,116,116,
+
+/* block 180 */
+779,779,779,779,779,779,779,779,779,116,779,779,779,779,779,779,
+779,779,779,779,779,779,779,779,779,779,779,779,779,779,779,779,
+779,779,779,779,779,779,779,779,779,779,779,779,779,779,779,780,
+781,781,781,781,781,781,781,116,781,781,781,781,781,781,780,781,
+779,782,782,782,782,782,116,116,116,116,116,116,116,116,116,116,
+783,783,783,783,783,783,783,783,783,783,784,784,784,784,784,784,
+784,784,784,784,784,784,784,784,784,784,784,784,784,116,116,116,
+785,785,786,786,786,786,786,786,786,786,786,786,786,786,786,786,
+
+/* block 181 */
+786,786,786,786,786,786,786,786,786,786,786,786,786,786,786,786,
+116,116,787,787,787,787,787,787,787,787,787,787,787,787,787,787,
+787,787,787,787,787,787,787,787,116,788,787,787,787,787,787,787,
+787,788,787,787,788,787,787,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 182 */
+789,789,789,789,789,789,789,116,789,789,116,789,789,789,789,789,
+789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,
+789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,789,
+789,790,790,790,790,790,790,116,116,116,790,116,790,790,116,790,
+790,790,790,790,790,790,791,790,116,116,116,116,116,116,116,116,
+792,792,792,792,792,792,792,792,792,792,116,116,116,116,116,116,
+793,793,793,793,793,793,116,793,793,116,793,793,793,793,793,793,
+793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,793,
+
+/* block 183 */
+793,793,793,793,793,793,793,793,793,793,794,794,794,794,794,116,
+795,795,116,794,794,795,794,795,793,116,116,116,116,116,116,116,
+796,796,796,796,796,796,796,796,796,796,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 184 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,797,
+797,797,797,798,798,799,799,800,800,116,116,116,116,116,116,116,
+
+/* block 185 */
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+
+/* block 186 */
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 187 */
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,
+802,802,802,802,802,802,802,802,802,802,802,802,802,802,802,116,
+803,803,803,803,803,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 188 */
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,801,
+801,801,801,801,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 189 */
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+
+/* block 190 */
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,
+804,804,804,804,804,804,804,804,804,804,804,804,804,804,804,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 191 */
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+
+/* block 192 */
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,805,
+805,805,805,805,805,805,805,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 193 */
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+
+/* block 194 */
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,538,
+538,538,538,538,538,538,538,538,538,116,116,116,116,116,116,116,
+806,806,806,806,806,806,806,806,806,806,806,806,806,806,806,806,
+806,806,806,806,806,806,806,806,806,806,806,806,806,806,806,116,
+807,807,807,807,807,807,807,807,807,807,116,116,116,116,808,808,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 195 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,809,
+809,809,809,809,809,809,809,809,809,809,809,809,809,809,116,116,
+810,810,810,810,810,811,116,116,116,116,116,116,116,116,116,116,
+
+/* block 196 */
+812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,
+812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,
+812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,
+813,813,813,813,813,813,813,814,814,814,814,814,815,815,815,815,
+816,816,816,816,814,815,116,116,116,116,116,116,116,116,116,116,
+817,817,817,817,817,817,817,817,817,817,116,818,818,818,818,818,
+818,818,116,812,812,812,812,812,812,812,812,812,812,812,812,812,
+812,812,812,812,812,812,812,812,116,116,116,116,116,812,812,812,
+
+/* block 197 */
+812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,812,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 198 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,819,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,820,
+
+/* block 199 */
+821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,821,
+821,821,821,821,821,821,821,822,822,822,822,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 200 */
+823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,
+823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,
+823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,
+823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,823,
+823,823,823,823,823,116,116,116,116,116,116,116,116,116,116,116,
+823,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,
+824,824,824,824,824,824,824,824,824,824,824,824,824,824,824,116,
+
+/* block 201 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,825,
+825,825,825,826,826,826,826,826,826,826,826,826,826,826,826,826,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+827,828,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 202 */
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+
+/* block 203 */
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 204 */
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,829,
+829,829,829,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 205 */
+517,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+
+/* block 206 */
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+
+/* block 207 */
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,
+515,515,515,515,515,515,515,515,515,515,515,515,515,515,515,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+
+/* block 208 */
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+
+/* block 209 */
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,830,
+830,830,830,830,830,830,830,830,830,830,830,830,116,116,116,116,
+
+/* block 210 */
+831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
+831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
+831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
+831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
+831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
+831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,831,
+831,831,831,831,831,831,831,831,831,831,831,116,116,116,116,116,
+831,831,831,831,831,831,831,831,831,831,831,831,831,116,116,116,
+
+/* block 211 */
+831,831,831,831,831,831,831,831,831,116,116,116,116,116,116,116,
+831,831,831,831,831,831,831,831,831,831,116,116,832,833,833,834,
+ 23, 23, 23, 23,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 212 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19,116,116,116,116,116,116,116,116,116,116,
+
+/* block 213 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19,116,116, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19,835,438,111,111,111, 19, 19, 19,438,835,835,
+835,835,835, 23, 23, 23, 23, 23, 23, 23, 23,111,111,111,111,111,
+
+/* block 214 */
+111,111,111, 19, 19,111,111,111,111,111,111,111, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,111,111,111,111, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 215 */
+604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,
+604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,
+604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,
+604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,604,
+604,604,836,836,836,604,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 216 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 217 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19,116,116,116,116,116,116,116,116,116,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24,116,116,116,116,116,116,116,
+
+/* block 218 */
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,473,473,
+473,473,473,473,473,116,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+
+/* block 219 */
+472,472,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,472,116,472,472,
+116,116,472,116,116,472,472,116,116,472,472,472,472,116,472,472,
+472,472,472,472,472,472,473,473,473,473,116,473,116,473,473,473,
+473,473,473,473,116,473,473,473,473,473,473,473,473,473,473,473,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+
+/* block 220 */
+473,473,473,473,472,472,116,472,472,472,472,116,116,472,472,472,
+472,472,472,472,472,116,472,472,472,472,472,472,472,116,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,472,472,116,472,472,472,472,116,
+472,472,472,472,472,116,472,116,116,116,472,472,472,472,472,472,
+472,116,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+
+/* block 221 */
+472,472,472,472,472,472,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+
+/* block 222 */
+473,473,473,473,473,473,473,473,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+
+/* block 223 */
+472,472,472,472,472,472,472,472,472,472,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,116,116,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472, 8,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473, 8,473,473,473,473,
+473,473,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472, 8,473,473,473,473,
+
+/* block 224 */
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473, 8,473,473,473,473,473,473,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472, 8,473,473,473,473,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473, 8,
+473,473,473,473,473,473,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472, 8,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+
+/* block 225 */
+473,473,473,473,473,473,473,473,473, 8,473,473,473,473,473,473,
+472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,
+472,472,472,472,472,472,472,472,472, 8,473,473,473,473,473,473,
+473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,473,
+473,473,473, 8,473,473,473,473,473,473,472,473,116,116, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+
+/* block 226 */
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,837,
+
+/* block 227 */
+838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,837,837,837,837,838,838,838,838,838,
+838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+838,838,838,838,838,838,838,838,838,838,838,838,838,837,837,837,
+837,837,837,837,837,838,837,837,837,837,837,837,837,837,837,837,
+
+/* block 228 */
+837,837,837,837,838,837,837,839,839,839,839,839,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,838,838,838,838,838,
+116,838,838,838,838,838,838,838,838,838,838,838,838,838,838,838,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 229 */
+840,840,840,840,840,840,840,116,840,840,840,840,840,840,840,840,
+840,840,840,840,840,840,840,840,840,116,116,840,840,840,840,840,
+840,840,116,840,840,116,840,840,840,840,840,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 230 */
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+
+/* block 231 */
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,841,
+841,841,841,841,841,116,116,842,842,842,842,842,842,842,842,842,
+843,843,843,843,843,843,843,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 232 */
+844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,
+844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,844,
+844,844,845,845,845,845,845,845,845,845,845,845,845,845,845,845,
+845,845,845,845,845,845,845,845,845,845,845,845,845,845,845,845,
+845,845,845,845,846,846,846,846,846,846,846,116,116,116,116,116,
+847,847,847,847,847,847,847,847,847,847,116,116,116,116,848,848,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 233 */
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+
+/* block 234 */
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 19, 24, 24, 24,
+ 5, 24, 24, 24, 24,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 235 */
+217,217,217,217,116,217,217,217,217,217,217,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,
+116,217,217,116,217,116,116,217,116,217,217,217,217,217,217,217,
+217,217,217,116,217,217,217,217,116,217,116,217,116,116,116,116,
+116,116,217,116,116,116,116,217,116,217,116,217,116,217,217,217,
+116,217,217,116,217,116,116,217,116,217,116,217,116,217,116,217,
+116,217,217,116,217,116,116,217,217,217,217,116,217,217,217,217,
+217,217,217,116,217,217,217,217,116,217,217,217,217,116,217,116,
+
+/* block 236 */
+217,217,217,217,217,217,217,217,217,217,116,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,116,116,116,116,
+116,217,217,217,116,217,217,217,217,217,116,217,217,217,217,217,
+217,217,217,217,217,217,217,217,217,217,217,217,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+211,211,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 237 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 238 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20,849,849,849,849,849,849,849,849,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,849,
+849, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+849, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+849, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20,849,849,849,849,849,849,849,849,849,849,
+
+/* block 239 */
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,
+ 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20,
+
+/* block 240 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 19,
+ 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,850,850,850,850,850,850,850,850,850,850,
+850,850,850,850,850,850,850,850,850,850,850,850,850,850,850,850,
+
+/* block 241 */
+851, 20, 20,849,849,849,849,849,849,849,849,849,849,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20,
+ 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19,849,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,849,849,849,
+ 20, 20,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+ 20, 20, 20, 20, 20, 20,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+
+/* block 242 */
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+
+/* block 243 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 244 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,852,852,852,852,852,
+
+/* block 245 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 19,
+ 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 246 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 247 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20,849,849,849,849,849,849,849,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,849,849,849,849,849,849,
+
+/* block 248 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19,849,849,849,849,849,849,849,849,849,849,849,849,
+
+/* block 249 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 20, 20, 20, 20,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+
+/* block 250 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,849,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+
+/* block 251 */
+ 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,849,849,849,849,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+
+/* block 252 */
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 19, 20, 20, 20,849,
+ 20, 20, 20, 20, 20, 20, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20,849,849, 20, 20, 20, 20,849,849,849, 20,849, 20, 20, 20, 20,
+
+/* block 253 */
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20,849,849,849,849,849,849,849,849,849,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,849,849,849,849,849,849,
+ 20, 20, 20,849,849,849,849,849,849,849,849,849,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+
+/* block 254 */
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+
+/* block 255 */
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,849,
+849,849,849,849,849,849,849,849,849,849,849,849,849,849,116,116,
+
+/* block 256 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 257 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,116,116,116,116,116,116,116,116,116,116,116,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+
+/* block 258 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,116,116,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+
+/* block 259 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+
+/* block 260 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 261 */
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,523,
+523,523,523,523,523,523,523,523,523,523,523,523,523,523,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
+
+/* block 262 */
+471, 23,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,853,
+
+/* block 263 */
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+
+/* block 264 */
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+
+/* block 265 */
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,
+471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,471,
+
+/* block 266 */
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,597,
+597,597,597,597,597,597,597,597,597,597,597,597,597,597,116,116,
+
+};
+
+#if UCD_BLOCK_SIZE != 128
+#error Please correct UCD_BLOCK_SIZE in pcre2_internal.h
+#endif
+#endif /* SUPPORT_UNICODE */
+
+#endif /* PCRE2_PCRE2TEST */
diff --git a/test/monniaux/pcre2-10.32/pcre2_ucp.h b/test/monniaux/pcre2-10.32/pcre2_ucp.h
new file mode 100644
index 00000000..0c330edc
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_ucp.h
@@ -0,0 +1,288 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+#ifndef PCRE2_UCP_H_IDEMPOTENT_GUARD
+#define PCRE2_UCP_H_IDEMPOTENT_GUARD
+
+/* This file contains definitions of the property values that are returned by
+the UCD access macros. New values that are added for new releases of Unicode
+should always be at the end of each enum, for backwards compatibility.
+
+IMPORTANT: Note also that the specific numeric values of the enums have to be
+the same as the values that are generated by the maint/MultiStage2.py script,
+where the equivalent property descriptive names are listed in vectors.
+
+ALSO: The specific values of the first two enums are assumed for the table
+called catposstab in pcre2_compile.c. */
+
+/* These are the general character categories. */
+
+enum {
+ ucp_C, /* Other */
+ ucp_L, /* Letter */
+ ucp_M, /* Mark */
+ ucp_N, /* Number */
+ ucp_P, /* Punctuation */
+ ucp_S, /* Symbol */
+ ucp_Z /* Separator */
+};
+
+/* These are the particular character categories. */
+
+enum {
+ ucp_Cc, /* Control */
+ ucp_Cf, /* Format */
+ ucp_Cn, /* Unassigned */
+ ucp_Co, /* Private use */
+ ucp_Cs, /* Surrogate */
+ ucp_Ll, /* Lower case letter */
+ ucp_Lm, /* Modifier letter */
+ ucp_Lo, /* Other letter */
+ ucp_Lt, /* Title case letter */
+ ucp_Lu, /* Upper case letter */
+ ucp_Mc, /* Spacing mark */
+ ucp_Me, /* Enclosing mark */
+ ucp_Mn, /* Non-spacing mark */
+ ucp_Nd, /* Decimal number */
+ ucp_Nl, /* Letter number */
+ ucp_No, /* Other number */
+ ucp_Pc, /* Connector punctuation */
+ ucp_Pd, /* Dash punctuation */
+ ucp_Pe, /* Close punctuation */
+ ucp_Pf, /* Final punctuation */
+ ucp_Pi, /* Initial punctuation */
+ ucp_Po, /* Other punctuation */
+ ucp_Ps, /* Open punctuation */
+ ucp_Sc, /* Currency symbol */
+ ucp_Sk, /* Modifier symbol */
+ ucp_Sm, /* Mathematical symbol */
+ ucp_So, /* Other symbol */
+ ucp_Zl, /* Line separator */
+ ucp_Zp, /* Paragraph separator */
+ ucp_Zs /* Space separator */
+};
+
+/* These are grapheme break properties. The Extended Pictographic property
+comes from the emoji-data.txt file. */
+
+enum {
+ ucp_gbCR, /* 0 */
+ ucp_gbLF, /* 1 */
+ ucp_gbControl, /* 2 */
+ ucp_gbExtend, /* 3 */
+ ucp_gbPrepend, /* 4 */
+ ucp_gbSpacingMark, /* 5 */
+ ucp_gbL, /* 6 Hangul syllable type L */
+ ucp_gbV, /* 7 Hangul syllable type V */
+ ucp_gbT, /* 8 Hangul syllable type T */
+ ucp_gbLV, /* 9 Hangul syllable type LV */
+ ucp_gbLVT, /* 10 Hangul syllable type LVT */
+ ucp_gbRegionalIndicator, /* 11 */
+ ucp_gbOther, /* 12 */
+ ucp_gbZWJ, /* 13 */
+ ucp_gbExtended_Pictographic /* 14 */
+};
+
+/* These are the script identifications. */
+
+enum {
+ ucp_Arabic,
+ ucp_Armenian,
+ ucp_Bengali,
+ ucp_Bopomofo,
+ ucp_Braille,
+ ucp_Buginese,
+ ucp_Buhid,
+ ucp_Canadian_Aboriginal,
+ ucp_Cherokee,
+ ucp_Common,
+ ucp_Coptic,
+ ucp_Cypriot,
+ ucp_Cyrillic,
+ ucp_Deseret,
+ ucp_Devanagari,
+ ucp_Ethiopic,
+ ucp_Georgian,
+ ucp_Glagolitic,
+ ucp_Gothic,
+ ucp_Greek,
+ ucp_Gujarati,
+ ucp_Gurmukhi,
+ ucp_Han,
+ ucp_Hangul,
+ ucp_Hanunoo,
+ ucp_Hebrew,
+ ucp_Hiragana,
+ ucp_Inherited,
+ ucp_Kannada,
+ ucp_Katakana,
+ ucp_Kharoshthi,
+ ucp_Khmer,
+ ucp_Lao,
+ ucp_Latin,
+ ucp_Limbu,
+ ucp_Linear_B,
+ ucp_Malayalam,
+ ucp_Mongolian,
+ ucp_Myanmar,
+ ucp_New_Tai_Lue,
+ ucp_Ogham,
+ ucp_Old_Italic,
+ ucp_Old_Persian,
+ ucp_Oriya,
+ ucp_Osmanya,
+ ucp_Runic,
+ ucp_Shavian,
+ ucp_Sinhala,
+ ucp_Syloti_Nagri,
+ ucp_Syriac,
+ ucp_Tagalog,
+ ucp_Tagbanwa,
+ ucp_Tai_Le,
+ ucp_Tamil,
+ ucp_Telugu,
+ ucp_Thaana,
+ ucp_Thai,
+ ucp_Tibetan,
+ ucp_Tifinagh,
+ ucp_Ugaritic,
+ ucp_Yi,
+ /* New for Unicode 5.0 */
+ ucp_Balinese,
+ ucp_Cuneiform,
+ ucp_Nko,
+ ucp_Phags_Pa,
+ ucp_Phoenician,
+ /* New for Unicode 5.1 */
+ ucp_Carian,
+ ucp_Cham,
+ ucp_Kayah_Li,
+ ucp_Lepcha,
+ ucp_Lycian,
+ ucp_Lydian,
+ ucp_Ol_Chiki,
+ ucp_Rejang,
+ ucp_Saurashtra,
+ ucp_Sundanese,
+ ucp_Vai,
+ /* New for Unicode 5.2 */
+ ucp_Avestan,
+ ucp_Bamum,
+ ucp_Egyptian_Hieroglyphs,
+ ucp_Imperial_Aramaic,
+ ucp_Inscriptional_Pahlavi,
+ ucp_Inscriptional_Parthian,
+ ucp_Javanese,
+ ucp_Kaithi,
+ ucp_Lisu,
+ ucp_Meetei_Mayek,
+ ucp_Old_South_Arabian,
+ ucp_Old_Turkic,
+ ucp_Samaritan,
+ ucp_Tai_Tham,
+ ucp_Tai_Viet,
+ /* New for Unicode 6.0.0 */
+ ucp_Batak,
+ ucp_Brahmi,
+ ucp_Mandaic,
+ /* New for Unicode 6.1.0 */
+ ucp_Chakma,
+ ucp_Meroitic_Cursive,
+ ucp_Meroitic_Hieroglyphs,
+ ucp_Miao,
+ ucp_Sharada,
+ ucp_Sora_Sompeng,
+ ucp_Takri,
+ /* New for Unicode 7.0.0 */
+ ucp_Bassa_Vah,
+ ucp_Caucasian_Albanian,
+ ucp_Duployan,
+ ucp_Elbasan,
+ ucp_Grantha,
+ ucp_Khojki,
+ ucp_Khudawadi,
+ ucp_Linear_A,
+ ucp_Mahajani,
+ ucp_Manichaean,
+ ucp_Mende_Kikakui,
+ ucp_Modi,
+ ucp_Mro,
+ ucp_Nabataean,
+ ucp_Old_North_Arabian,
+ ucp_Old_Permic,
+ ucp_Pahawh_Hmong,
+ ucp_Palmyrene,
+ ucp_Psalter_Pahlavi,
+ ucp_Pau_Cin_Hau,
+ ucp_Siddham,
+ ucp_Tirhuta,
+ ucp_Warang_Citi,
+ /* New for Unicode 8.0.0 */
+ ucp_Ahom,
+ ucp_Anatolian_Hieroglyphs,
+ ucp_Hatran,
+ ucp_Multani,
+ ucp_Old_Hungarian,
+ ucp_SignWriting,
+ /* New for Unicode 10.0.0 (no update since 8.0.0) */
+ ucp_Adlam,
+ ucp_Bhaiksuki,
+ ucp_Marchen,
+ ucp_Newa,
+ ucp_Osage,
+ ucp_Tangut,
+ ucp_Masaram_Gondi,
+ ucp_Nushu,
+ ucp_Soyombo,
+ ucp_Zanabazar_Square,
+ /* New for Unicode 11.0.0 */
+ ucp_Dogra,
+ ucp_Gunjala_Gondi,
+ ucp_Hanifi_Rohingya,
+ ucp_Makasar,
+ ucp_Medefaidrin,
+ ucp_Old_Sogdian,
+ ucp_Sogdian
+};
+
+#endif /* PCRE2_UCP_H_IDEMPOTENT_GUARD */
+
+/* End of pcre2_ucp.h */
diff --git a/test/monniaux/pcre2-10.32/pcre2_valid_utf.c b/test/monniaux/pcre2-10.32/pcre2_valid_utf.c
new file mode 100644
index 00000000..96e8bff9
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_valid_utf.c
@@ -0,0 +1,398 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2017 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module contains an internal function for validating UTF character
+strings. This file is also #included by the pcre2test program, which uses
+macros to change names from _pcre2_xxx to xxxx, thereby avoiding name clashes
+with the library. In this case, PCRE2_PCRE2TEST is defined. */
+
+#ifndef PCRE2_PCRE2TEST /* We're compiling the library */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pcre2_internal.h"
+#endif /* PCRE2_PCRE2TEST */
+
+
+#ifndef SUPPORT_UNICODE
+/*************************************************
+* Dummy function when Unicode is not supported *
+*************************************************/
+
+/* This function should never be called when Unicode is not supported. */
+
+int
+PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset)
+{
+(void)string;
+(void)length;
+(void)erroroffset;
+return 0;
+}
+#else /* UTF is supported */
+
+
+
+/*************************************************
+* Validate a UTF string *
+*************************************************/
+
+/* This function is called (optionally) at the start of compile or match, to
+check that a supposed UTF string is actually valid. The early check means
+that subsequent code can assume it is dealing with a valid string. The check
+can be turned off for maximum performance, but the consequences of supplying an
+invalid string are then undefined.
+
+Arguments:
+ string points to the string
+ length length of string
+ errp pointer to an error position offset variable
+
+Returns: == 0 if the string is a valid UTF string
+ != 0 otherwise, setting the offset of the bad character
+*/
+
+int
+PRIV(valid_utf)(PCRE2_SPTR string, PCRE2_SIZE length, PCRE2_SIZE *erroroffset)
+{
+PCRE2_SPTR p;
+uint32_t c;
+
+/* ----------------- Check a UTF-8 string ----------------- */
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+
+/* Originally, this function checked according to RFC 2279, allowing for values
+in the range 0 to 0x7fffffff, up to 6 bytes long, but ensuring that they were
+in the canonical format. Once somebody had pointed out RFC 3629 to me (it
+obsoletes 2279), additional restrictions were applied. The values are now
+limited to be between 0 and 0x0010ffff, no more than 4 bytes long, and the
+subrange 0xd000 to 0xdfff is excluded. However, the format of 5-byte and 6-byte
+characters is still checked. Error returns are as follows:
+
+PCRE2_ERROR_UTF8_ERR1 Missing 1 byte at the end of the string
+PCRE2_ERROR_UTF8_ERR2 Missing 2 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR3 Missing 3 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR4 Missing 4 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR5 Missing 5 bytes at the end of the string
+PCRE2_ERROR_UTF8_ERR6 2nd-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR7 3rd-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR8 4th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR9 5th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR10 6th-byte's two top bits are not 0x80
+PCRE2_ERROR_UTF8_ERR11 5-byte character is not permitted by RFC 3629
+PCRE2_ERROR_UTF8_ERR12 6-byte character is not permitted by RFC 3629
+PCRE2_ERROR_UTF8_ERR13 4-byte character with value > 0x10ffff is not permitted
+PCRE2_ERROR_UTF8_ERR14 3-byte character with value 0xd800-0xdfff is not permitted
+PCRE2_ERROR_UTF8_ERR15 Overlong 2-byte sequence
+PCRE2_ERROR_UTF8_ERR16 Overlong 3-byte sequence
+PCRE2_ERROR_UTF8_ERR17 Overlong 4-byte sequence
+PCRE2_ERROR_UTF8_ERR18 Overlong 5-byte sequence (won't ever occur)
+PCRE2_ERROR_UTF8_ERR19 Overlong 6-byte sequence (won't ever occur)
+PCRE2_ERROR_UTF8_ERR20 Isolated 0x80 byte (not within UTF-8 character)
+PCRE2_ERROR_UTF8_ERR21 Byte with the illegal value 0xfe or 0xff
+*/
+
+for (p = string; length > 0; p++)
+ {
+ uint32_t ab, d;
+
+ c = *p;
+ length--;
+
+ if (c < 128) continue; /* ASCII character */
+
+ if (c < 0xc0) /* Isolated 10xx xxxx byte */
+ {
+ *erroroffset = (PCRE2_SIZE)(p - string);
+ return PCRE2_ERROR_UTF8_ERR20;
+ }
+
+ if (c >= 0xfe) /* Invalid 0xfe or 0xff bytes */
+ {
+ *erroroffset = (PCRE2_SIZE)(p - string);
+ return PCRE2_ERROR_UTF8_ERR21;
+ }
+
+ ab = PRIV(utf8_table4)[c & 0x3f]; /* Number of additional bytes (1-5) */
+ if (length < ab) /* Missing bytes */
+ {
+ *erroroffset = (PCRE2_SIZE)(p - string);
+ switch(ab - length)
+ {
+ case 1: return PCRE2_ERROR_UTF8_ERR1;
+ case 2: return PCRE2_ERROR_UTF8_ERR2;
+ case 3: return PCRE2_ERROR_UTF8_ERR3;
+ case 4: return PCRE2_ERROR_UTF8_ERR4;
+ case 5: return PCRE2_ERROR_UTF8_ERR5;
+ }
+ }
+ length -= ab; /* Length remaining */
+
+ /* Check top bits in the second byte */
+
+ if (((d = *(++p)) & 0xc0) != 0x80)
+ {
+ *erroroffset = (int)(p - string) - 1;
+ return PCRE2_ERROR_UTF8_ERR6;
+ }
+
+ /* For each length, check that the remaining bytes start with the 0x80 bit
+ set and not the 0x40 bit. Then check for an overlong sequence, and for the
+ excluded range 0xd800 to 0xdfff. */
+
+ switch (ab)
+ {
+ /* 2-byte character. No further bytes to check for 0x80. Check first byte
+ for for xx00 000x (overlong sequence). */
+
+ case 1: if ((c & 0x3e) == 0)
+ {
+ *erroroffset = (int)(p - string) - 1;
+ return PCRE2_ERROR_UTF8_ERR15;
+ }
+ break;
+
+ /* 3-byte character. Check third byte for 0x80. Then check first 2 bytes
+ for 1110 0000, xx0x xxxx (overlong sequence) or
+ 1110 1101, 1010 xxxx (0xd800 - 0xdfff) */
+
+ case 2:
+ if ((*(++p) & 0xc0) != 0x80) /* Third byte */
+ {
+ *erroroffset = (int)(p - string) - 2;
+ return PCRE2_ERROR_UTF8_ERR7;
+ }
+ if (c == 0xe0 && (d & 0x20) == 0)
+ {
+ *erroroffset = (int)(p - string) - 2;
+ return PCRE2_ERROR_UTF8_ERR16;
+ }
+ if (c == 0xed && d >= 0xa0)
+ {
+ *erroroffset = (int)(p - string) - 2;
+ return PCRE2_ERROR_UTF8_ERR14;
+ }
+ break;
+
+ /* 4-byte character. Check 3rd and 4th bytes for 0x80. Then check first 2
+ bytes for for 1111 0000, xx00 xxxx (overlong sequence), then check for a
+ character greater than 0x0010ffff (f4 8f bf bf) */
+
+ case 3:
+ if ((*(++p) & 0xc0) != 0x80) /* Third byte */
+ {
+ *erroroffset = (int)(p - string) - 2;
+ return PCRE2_ERROR_UTF8_ERR7;
+ }
+ if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
+ {
+ *erroroffset = (int)(p - string) - 3;
+ return PCRE2_ERROR_UTF8_ERR8;
+ }
+ if (c == 0xf0 && (d & 0x30) == 0)
+ {
+ *erroroffset = (int)(p - string) - 3;
+ return PCRE2_ERROR_UTF8_ERR17;
+ }
+ if (c > 0xf4 || (c == 0xf4 && d > 0x8f))
+ {
+ *erroroffset = (int)(p - string) - 3;
+ return PCRE2_ERROR_UTF8_ERR13;
+ }
+ break;
+
+ /* 5-byte and 6-byte characters are not allowed by RFC 3629, and will be
+ rejected by the length test below. However, we do the appropriate tests
+ here so that overlong sequences get diagnosed, and also in case there is
+ ever an option for handling these larger code points. */
+
+ /* 5-byte character. Check 3rd, 4th, and 5th bytes for 0x80. Then check for
+ 1111 1000, xx00 0xxx */
+
+ case 4:
+ if ((*(++p) & 0xc0) != 0x80) /* Third byte */
+ {
+ *erroroffset = (int)(p - string) - 2;
+ return PCRE2_ERROR_UTF8_ERR7;
+ }
+ if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
+ {
+ *erroroffset = (int)(p - string) - 3;
+ return PCRE2_ERROR_UTF8_ERR8;
+ }
+ if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
+ {
+ *erroroffset = (int)(p - string) - 4;
+ return PCRE2_ERROR_UTF8_ERR9;
+ }
+ if (c == 0xf8 && (d & 0x38) == 0)
+ {
+ *erroroffset = (int)(p - string) - 4;
+ return PCRE2_ERROR_UTF8_ERR18;
+ }
+ break;
+
+ /* 6-byte character. Check 3rd-6th bytes for 0x80. Then check for
+ 1111 1100, xx00 00xx. */
+
+ case 5:
+ if ((*(++p) & 0xc0) != 0x80) /* Third byte */
+ {
+ *erroroffset = (int)(p - string) - 2;
+ return PCRE2_ERROR_UTF8_ERR7;
+ }
+ if ((*(++p) & 0xc0) != 0x80) /* Fourth byte */
+ {
+ *erroroffset = (int)(p - string) - 3;
+ return PCRE2_ERROR_UTF8_ERR8;
+ }
+ if ((*(++p) & 0xc0) != 0x80) /* Fifth byte */
+ {
+ *erroroffset = (int)(p - string) - 4;
+ return PCRE2_ERROR_UTF8_ERR9;
+ }
+ if ((*(++p) & 0xc0) != 0x80) /* Sixth byte */
+ {
+ *erroroffset = (int)(p - string) - 5;
+ return PCRE2_ERROR_UTF8_ERR10;
+ }
+ if (c == 0xfc && (d & 0x3c) == 0)
+ {
+ *erroroffset = (int)(p - string) - 5;
+ return PCRE2_ERROR_UTF8_ERR19;
+ }
+ break;
+ }
+
+ /* Character is valid under RFC 2279, but 4-byte and 5-byte characters are
+ excluded by RFC 3629. The pointer p is currently at the last byte of the
+ character. */
+
+ if (ab > 3)
+ {
+ *erroroffset = (int)(p - string) - ab;
+ return (ab == 4)? PCRE2_ERROR_UTF8_ERR11 : PCRE2_ERROR_UTF8_ERR12;
+ }
+ }
+return 0;
+
+
+/* ----------------- Check a UTF-16 string ----------------- */
+
+#elif PCRE2_CODE_UNIT_WIDTH == 16
+
+/* There's not so much work, nor so many errors, for UTF-16.
+PCRE2_ERROR_UTF16_ERR1 Missing low surrogate at the end of the string
+PCRE2_ERROR_UTF16_ERR2 Invalid low surrogate
+PCRE2_ERROR_UTF16_ERR3 Isolated low surrogate
+*/
+
+for (p = string; length > 0; p++)
+ {
+ c = *p;
+ length--;
+
+ if ((c & 0xf800) != 0xd800)
+ {
+ /* Normal UTF-16 code point. Neither high nor low surrogate. */
+ }
+ else if ((c & 0x0400) == 0)
+ {
+ /* High surrogate. Must be a followed by a low surrogate. */
+ if (length == 0)
+ {
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF16_ERR1;
+ }
+ p++;
+ length--;
+ if ((*p & 0xfc00) != 0xdc00)
+ {
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF16_ERR2;
+ }
+ }
+ else
+ {
+ /* Isolated low surrogate. Always an error. */
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF16_ERR3;
+ }
+ }
+return 0;
+
+
+
+/* ----------------- Check a UTF-32 string ----------------- */
+
+#else
+
+/* There is very little to do for a UTF-32 string.
+PCRE2_ERROR_UTF32_ERR1 Surrogate character
+PCRE2_ERROR_UTF32_ERR2 Character > 0x10ffff
+*/
+
+for (p = string; length > 0; length--, p++)
+ {
+ c = *p;
+ if ((c & 0xfffff800u) != 0xd800u)
+ {
+ /* Normal UTF-32 code point. Neither high nor low surrogate. */
+ if (c > 0x10ffffu)
+ {
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF32_ERR2;
+ }
+ }
+ else
+ {
+ /* A surrogate */
+ *erroroffset = p - string;
+ return PCRE2_ERROR_UTF32_ERR1;
+ }
+ }
+return 0;
+#endif /* CODE_UNIT_WIDTH */
+}
+#endif /* SUPPORT_UNICODE */
+
+/* End of pcre2_valid_utf.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2_xclass.c b/test/monniaux/pcre2-10.32/pcre2_xclass.c
new file mode 100644
index 00000000..407d3f5b
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2_xclass.c
@@ -0,0 +1,271 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+/* This module contains an internal function that is used to match an extended
+class. It is used by pcre2_auto_possessify() and by both pcre2_match() and
+pcre2_def_match(). */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "pcre2_internal.h"
+
+/*************************************************
+* Match character against an XCLASS *
+*************************************************/
+
+/* This function is called to match a character against an extended class that
+might contain codepoints above 255 and/or Unicode properties.
+
+Arguments:
+ c the character
+ data points to the flag code unit of the XCLASS data
+ utf TRUE if in UTF mode
+
+Returns: TRUE if character matches, else FALSE
+*/
+
+BOOL
+PRIV(xclass)(uint32_t c, PCRE2_SPTR data, BOOL utf)
+{
+PCRE2_UCHAR t;
+BOOL negated = (*data & XCL_NOT) != 0;
+
+#if PCRE2_CODE_UNIT_WIDTH == 8
+/* In 8 bit mode, this must always be TRUE. Help the compiler to know that. */
+utf = TRUE;
+#endif
+
+/* Code points < 256 are matched against a bitmap, if one is present. If not,
+we still carry on, because there may be ranges that start below 256 in the
+additional data. */
+
+if (c < 256)
+ {
+ if ((*data & XCL_HASPROP) == 0)
+ {
+ if ((*data & XCL_MAP) == 0) return negated;
+ return (((uint8_t *)(data + 1))[c/8] & (1 << (c&7))) != 0;
+ }
+ if ((*data & XCL_MAP) != 0 &&
+ (((uint8_t *)(data + 1))[c/8] & (1 << (c&7))) != 0)
+ return !negated; /* char found */
+ }
+
+/* First skip the bit map if present. Then match against the list of Unicode
+properties or large chars or ranges that end with a large char. We won't ever
+encounter XCL_PROP or XCL_NOTPROP when UTF support is not compiled. */
+
+if ((*data++ & XCL_MAP) != 0) data += 32 / sizeof(PCRE2_UCHAR);
+
+while ((t = *data++) != XCL_END)
+ {
+ uint32_t x, y;
+ if (t == XCL_SINGLE)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ GETCHARINC(x, data); /* macro generates multiple statements */
+ }
+ else
+#endif
+ x = *data++;
+ if (c == x) return !negated;
+ }
+ else if (t == XCL_RANGE)
+ {
+#ifdef SUPPORT_UNICODE
+ if (utf)
+ {
+ GETCHARINC(x, data); /* macro generates multiple statements */
+ GETCHARINC(y, data); /* macro generates multiple statements */
+ }
+ else
+#endif
+ {
+ x = *data++;
+ y = *data++;
+ }
+ if (c >= x && c <= y) return !negated;
+ }
+
+#ifdef SUPPORT_UNICODE
+ else /* XCL_PROP & XCL_NOTPROP */
+ {
+ const ucd_record *prop = GET_UCD(c);
+ BOOL isprop = t == XCL_PROP;
+
+ switch(*data)
+ {
+ case PT_ANY:
+ if (isprop) return !negated;
+ break;
+
+ case PT_LAMP:
+ if ((prop->chartype == ucp_Lu || prop->chartype == ucp_Ll ||
+ prop->chartype == ucp_Lt) == isprop) return !negated;
+ break;
+
+ case PT_GC:
+ if ((data[1] == PRIV(ucp_gentype)[prop->chartype]) == isprop)
+ return !negated;
+ break;
+
+ case PT_PC:
+ if ((data[1] == prop->chartype) == isprop) return !negated;
+ break;
+
+ case PT_SC:
+ if ((data[1] == prop->script) == isprop) return !negated;
+ break;
+
+ case PT_ALNUM:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N) == isprop)
+ return !negated;
+ break;
+
+ /* Perl space used to exclude VT, but from Perl 5.18 it is included,
+ which means that Perl space and POSIX space are now identical. PCRE
+ was changed at release 8.34. */
+
+ case PT_SPACE: /* Perl space */
+ case PT_PXSPACE: /* POSIX space */
+ switch(c)
+ {
+ HSPACE_CASES:
+ VSPACE_CASES:
+ if (isprop) return !negated;
+ break;
+
+ default:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == isprop)
+ return !negated;
+ break;
+ }
+ break;
+
+ case PT_WORD:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
+ PRIV(ucp_gentype)[prop->chartype] == ucp_N || c == CHAR_UNDERSCORE)
+ == isprop)
+ return !negated;
+ break;
+
+ case PT_UCNC:
+ if (c < 0xa0)
+ {
+ if ((c == CHAR_DOLLAR_SIGN || c == CHAR_COMMERCIAL_AT ||
+ c == CHAR_GRAVE_ACCENT) == isprop)
+ return !negated;
+ }
+ else
+ {
+ if ((c < 0xd800 || c > 0xdfff) == isprop)
+ return !negated;
+ }
+ break;
+
+ /* The following three properties can occur only in an XCLASS, as there
+ is no \p or \P coding for them. */
+
+ /* Graphic character. Implement this as not Z (space or separator) and
+ not C (other), except for Cf (format) with a few exceptions. This seems
+ to be what Perl does. The exceptional characters are:
+
+ U+061C Arabic Letter Mark
+ U+180E Mongolian Vowel Separator
+ U+2066 - U+2069 Various "isolate"s
+ */
+
+ case PT_PXGRAPH:
+ if ((PRIV(ucp_gentype)[prop->chartype] != ucp_Z &&
+ (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
+ (prop->chartype == ucp_Cf &&
+ c != 0x061c && c != 0x180e && (c < 0x2066 || c > 0x2069))
+ )) == isprop)
+ return !negated;
+ break;
+
+ /* Printable character: same as graphic, with the addition of Zs, i.e.
+ not Zl and not Zp, and U+180E. */
+
+ case PT_PXPRINT:
+ if ((prop->chartype != ucp_Zl &&
+ prop->chartype != ucp_Zp &&
+ (PRIV(ucp_gentype)[prop->chartype] != ucp_C ||
+ (prop->chartype == ucp_Cf &&
+ c != 0x061c && (c < 0x2066 || c > 0x2069))
+ )) == isprop)
+ return !negated;
+ break;
+
+ /* Punctuation: all Unicode punctuation, plus ASCII characters that
+ Unicode treats as symbols rather than punctuation, for Perl
+ compatibility (these are $+<=>^`|~). */
+
+ case PT_PXPUNCT:
+ if ((PRIV(ucp_gentype)[prop->chartype] == ucp_P ||
+ (c < 128 && PRIV(ucp_gentype)[prop->chartype] == ucp_S)) == isprop)
+ return !negated;
+ break;
+
+ /* This should never occur, but compilers may mutter if there is no
+ default. */
+
+ default:
+ return FALSE;
+ }
+
+ data += 2;
+ }
+#else
+ (void)utf; /* Avoid compiler warning */
+#endif /* SUPPORT_UNICODE */
+ }
+
+return negated; /* char did not match */
+}
+
+/* End of pcre2_xclass.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2posix.c b/test/monniaux/pcre2-10.32/pcre2posix.c
new file mode 100644
index 00000000..7b9f4774
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2posix.c
@@ -0,0 +1,375 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This module is a wrapper that provides a POSIX API to the underlying PCRE2
+functions. */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+/* Ensure that the PCRE2POSIX_EXP_xxx macros are set appropriately for
+compiling these functions. This must come before including pcre2posix.h, where
+they are set for an application (using these functions) if they have not
+previously been set. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC)
+# define PCRE2POSIX_EXP_DECL extern __declspec(dllexport)
+# define PCRE2POSIX_EXP_DEFN __declspec(dllexport)
+#endif
+
+/* Older versions of MSVC lack snprintf(). This define allows for
+warning/error-free compilation and testing with MSVC compilers back to at least
+MSVC 10/2010. Except for VC6 (which is missing some fundamentals and fails). */
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#define snprintf _snprintf
+#endif
+
+
+/* Compile-time error numbers start at this value. It should probably never be
+changed. This #define is a copy of the one in pcre2_internal.h. */
+
+#define COMPILE_ERROR_BASE 100
+
+
+/* Standard C headers */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* PCRE2 headers */
+
+#include "pcre2.h"
+#include "pcre2posix.h"
+
+/* When compiling with the MSVC compiler, it is sometimes necessary to include
+a "calling convention" before exported function names. (This is secondhand
+information; I know nothing about MSVC myself). For example, something like
+
+ void __cdecl function(....)
+
+might be needed. In order to make this easy, all the exported functions have
+PCRE2_CALL_CONVENTION just before their names. It is rarely needed; if not
+set, we ensure here that it has no effect. */
+
+#ifndef PCRE2_CALL_CONVENTION
+#define PCRE2_CALL_CONVENTION
+#endif
+
+/* Table to translate PCRE2 compile time error codes into POSIX error codes.
+Only a few PCRE2 errors with a value greater than 23 turn into special POSIX
+codes: most go to REG_BADPAT. The second table lists, in pairs, those that
+don't. */
+
+static const int eint1[] = {
+ 0, /* No error */
+ REG_EESCAPE, /* \ at end of pattern */
+ REG_EESCAPE, /* \c at end of pattern */
+ REG_EESCAPE, /* unrecognized character follows \ */
+ REG_BADBR, /* numbers out of order in {} quantifier */
+ /* 5 */
+ REG_BADBR, /* number too big in {} quantifier */
+ REG_EBRACK, /* missing terminating ] for character class */
+ REG_ECTYPE, /* invalid escape sequence in character class */
+ REG_ERANGE, /* range out of order in character class */
+ REG_BADRPT, /* nothing to repeat */
+ /* 10 */
+ REG_ASSERT, /* internal error: unexpected repeat */
+ REG_BADPAT, /* unrecognized character after (? or (?- */
+ REG_BADPAT, /* POSIX named classes are supported only within a class */
+ REG_BADPAT, /* POSIX collating elements are not supported */
+ REG_EPAREN, /* missing ) */
+ /* 15 */
+ REG_ESUBREG, /* reference to non-existent subpattern */
+ REG_INVARG, /* pattern passed as NULL */
+ REG_INVARG, /* unknown compile-time option bit(s) */
+ REG_EPAREN, /* missing ) after (?# comment */
+ REG_ESIZE, /* parentheses nested too deeply */
+ /* 20 */
+ REG_ESIZE, /* regular expression too large */
+ REG_ESPACE, /* failed to get memory */
+ REG_EPAREN, /* unmatched closing parenthesis */
+ REG_ASSERT /* internal error: code overflow */
+ };
+
+static const int eint2[] = {
+ 30, REG_ECTYPE, /* unknown POSIX class name */
+ 32, REG_INVARG, /* this version of PCRE2 does not have Unicode support */
+ 37, REG_EESCAPE, /* PCRE2 does not support \L, \l, \N{name}, \U, or \u */
+ 56, REG_INVARG, /* internal error: unknown newline setting */
+ 92, REG_INVARG, /* invalid option bits with PCRE2_LITERAL */
+};
+
+/* Table of texts corresponding to POSIX error codes */
+
+static const char *const pstring[] = {
+ "", /* Dummy for value 0 */
+ "internal error", /* REG_ASSERT */
+ "invalid repeat counts in {}", /* BADBR */
+ "pattern error", /* BADPAT */
+ "? * + invalid", /* BADRPT */
+ "unbalanced {}", /* EBRACE */
+ "unbalanced []", /* EBRACK */
+ "collation error - not relevant", /* ECOLLATE */
+ "bad class", /* ECTYPE */
+ "bad escape sequence", /* EESCAPE */
+ "empty expression", /* EMPTY */
+ "unbalanced ()", /* EPAREN */
+ "bad range inside []", /* ERANGE */
+ "expression too big", /* ESIZE */
+ "failed to get memory", /* ESPACE */
+ "bad back reference", /* ESUBREG */
+ "bad argument", /* INVARG */
+ "match failed" /* NOMATCH */
+};
+
+
+
+
+/*************************************************
+* Translate error code to string *
+*************************************************/
+
+PCRE2POSIX_EXP_DEFN size_t PCRE2_CALL_CONVENTION
+regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+int used;
+const char *message;
+
+message = (errcode <= 0 || errcode >= (int)(sizeof(pstring)/sizeof(char *)))?
+ "unknown error code" : pstring[errcode];
+
+if (preg != NULL && (int)preg->re_erroffset != -1)
+ {
+ used = snprintf(errbuf, errbuf_size, "%s at offset %-6d", message,
+ (int)preg->re_erroffset);
+ }
+else
+ {
+ used = snprintf(errbuf, errbuf_size, "%s", message);
+ }
+
+return used + 1;
+}
+
+
+
+
+/*************************************************
+* Free store held by a regex *
+*************************************************/
+
+PCRE2POSIX_EXP_DEFN void PCRE2_CALL_CONVENTION
+regfree(regex_t *preg)
+{
+pcre2_match_data_free(preg->re_match_data);
+pcre2_code_free(preg->re_pcre2_code);
+}
+
+
+
+
+/*************************************************
+* Compile a regular expression *
+*************************************************/
+
+/*
+Arguments:
+ preg points to a structure for recording the compiled expression
+ pattern the pattern to compile
+ cflags compilation flags
+
+Returns: 0 on success
+ various non-zero codes on failure
+*/
+
+PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION
+regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+PCRE2_SIZE erroffset;
+PCRE2_SIZE patlen;
+int errorcode;
+int options = 0;
+int re_nsub = 0;
+
+patlen = ((cflags & REG_PEND) != 0)? (PCRE2_SIZE)(preg->re_endp - pattern) :
+ PCRE2_ZERO_TERMINATED;
+
+if ((cflags & REG_ICASE) != 0) options |= PCRE2_CASELESS;
+if ((cflags & REG_NEWLINE) != 0) options |= PCRE2_MULTILINE;
+if ((cflags & REG_DOTALL) != 0) options |= PCRE2_DOTALL;
+if ((cflags & REG_NOSPEC) != 0) options |= PCRE2_LITERAL;
+if ((cflags & REG_UTF) != 0) options |= PCRE2_UTF;
+if ((cflags & REG_UCP) != 0) options |= PCRE2_UCP;
+if ((cflags & REG_UNGREEDY) != 0) options |= PCRE2_UNGREEDY;
+
+preg->re_cflags = cflags;
+preg->re_pcre2_code = pcre2_compile((PCRE2_SPTR)pattern, patlen, options,
+ &errorcode, &erroffset, NULL);
+preg->re_erroffset = erroffset;
+
+if (preg->re_pcre2_code == NULL)
+ {
+ unsigned int i;
+
+ /* A negative value is a UTF error; otherwise all error codes are greater
+ than COMPILE_ERROR_BASE, but check, just in case. */
+
+ if (errorcode < COMPILE_ERROR_BASE) return REG_BADPAT;
+ errorcode -= COMPILE_ERROR_BASE;
+
+ if (errorcode < (int)(sizeof(eint1)/sizeof(const int)))
+ return eint1[errorcode];
+ for (i = 0; i < sizeof(eint2)/sizeof(const int); i += 2)
+ if (errorcode == eint2[i]) return eint2[i+1];
+ return REG_BADPAT;
+ }
+
+(void)pcre2_pattern_info((const pcre2_code *)preg->re_pcre2_code,
+ PCRE2_INFO_CAPTURECOUNT, &re_nsub);
+preg->re_nsub = (size_t)re_nsub;
+preg->re_match_data = pcre2_match_data_create(re_nsub + 1, NULL);
+
+if (preg->re_match_data == NULL)
+ {
+ pcre2_code_free(preg->re_pcre2_code);
+ return REG_ESPACE;
+ }
+
+return 0;
+}
+
+
+
+/*************************************************
+* Match a regular expression *
+*************************************************/
+
+/* A suitable match_data block, large enough to hold all possible captures, was
+obtained when the pattern was compiled, to save having to allocate and free it
+for each match. If REG_NOSUB was specified at compile time, the nmatch and
+pmatch arguments are ignored, and the only result is yes/no/error. */
+
+PCRE2POSIX_EXP_DEFN int PCRE2_CALL_CONVENTION
+regexec(const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags)
+{
+int rc, so, eo;
+int options = 0;
+pcre2_match_data *md = (pcre2_match_data *)preg->re_match_data;
+
+if ((eflags & REG_NOTBOL) != 0) options |= PCRE2_NOTBOL;
+if ((eflags & REG_NOTEOL) != 0) options |= PCRE2_NOTEOL;
+if ((eflags & REG_NOTEMPTY) != 0) options |= PCRE2_NOTEMPTY;
+
+((regex_t *)preg)->re_erroffset = (size_t)(-1); /* Only has meaning after compile */
+
+/* When REG_NOSUB was specified, or if no vector has been passed in which to
+put captured strings, ensure that nmatch is zero. This will stop any attempt to
+write to pmatch. */
+
+if ((preg->re_cflags & REG_NOSUB) != 0 || pmatch == NULL) nmatch = 0;
+
+/* REG_STARTEND is a BSD extension, to allow for non-NUL-terminated strings.
+The man page from OS X says "REG_STARTEND affects only the location of the
+string, not how it is matched". That is why the "so" value is used to bump the
+start location rather than being passed as a PCRE2 "starting offset". */
+
+if ((eflags & REG_STARTEND) != 0)
+ {
+ if (pmatch == NULL) return REG_INVARG;
+ so = pmatch[0].rm_so;
+ eo = pmatch[0].rm_eo;
+ }
+else
+ {
+ so = 0;
+ eo = (int)strlen(string);
+ }
+
+rc = pcre2_match((const pcre2_code *)preg->re_pcre2_code,
+ (PCRE2_SPTR)string + so, (eo - so), 0, options, md, NULL);
+
+/* Successful match */
+
+if (rc >= 0)
+ {
+ size_t i;
+ PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(md);
+ if ((size_t)rc > nmatch) rc = (int)nmatch;
+ for (i = 0; i < (size_t)rc; i++)
+ {
+ pmatch[i].rm_so = (ovector[i*2] == PCRE2_UNSET)? -1 :
+ (int)(ovector[i*2] + so);
+ pmatch[i].rm_eo = (ovector[i*2+1] == PCRE2_UNSET)? -1 :
+ (int)(ovector[i*2+1] + so);
+ }
+ for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+ return 0;
+ }
+
+/* Unsuccessful match */
+
+if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21)
+ return REG_INVARG;
+
+switch(rc)
+ {
+ default: return REG_ASSERT;
+ case PCRE2_ERROR_BADMODE: return REG_INVARG;
+ case PCRE2_ERROR_BADMAGIC: return REG_INVARG;
+ case PCRE2_ERROR_BADOPTION: return REG_INVARG;
+ case PCRE2_ERROR_BADUTFOFFSET: return REG_INVARG;
+ case PCRE2_ERROR_MATCHLIMIT: return REG_ESPACE;
+ case PCRE2_ERROR_NOMATCH: return REG_NOMATCH;
+ case PCRE2_ERROR_NOMEMORY: return REG_ESPACE;
+ case PCRE2_ERROR_NULL: return REG_INVARG;
+ }
+}
+
+/* End of pcre2posix.c */
diff --git a/test/monniaux/pcre2-10.32/pcre2posix.h b/test/monniaux/pcre2-10.32/pcre2posix.h
new file mode 100644
index 00000000..4ae1d3c2
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2posix.h
@@ -0,0 +1,151 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* PCRE2 is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+ Written by Philip Hazel
+ Original API code Copyright (c) 1997-2012 University of Cambridge
+ New API code Copyright (c) 2016 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* Have to include stdlib.h in order to ensure that size_t is defined. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options, mostly defined by POSIX, but with some extras. */
+
+#define REG_ICASE 0x0001 /* Maps to PCRE2_CASELESS */
+#define REG_NEWLINE 0x0002 /* Maps to PCRE2_MULTILINE */
+#define REG_NOTBOL 0x0004 /* Maps to PCRE2_NOTBOL */
+#define REG_NOTEOL 0x0008 /* Maps to PCRE2_NOTEOL */
+#define REG_DOTALL 0x0010 /* NOT defined by POSIX; maps to PCRE2_DOTALL */
+#define REG_NOSUB 0x0020 /* Do not report what was matched */
+#define REG_UTF 0x0040 /* NOT defined by POSIX; maps to PCRE2_UTF */
+#define REG_STARTEND 0x0080 /* BSD feature: pass subject string by so,eo */
+#define REG_NOTEMPTY 0x0100 /* NOT defined by POSIX; maps to PCRE2_NOTEMPTY */
+#define REG_UNGREEDY 0x0200 /* NOT defined by POSIX; maps to PCRE2_UNGREEDY */
+#define REG_UCP 0x0400 /* NOT defined by POSIX; maps to PCRE2_UCP */
+#define REG_PEND 0x0800 /* GNU feature: pass end pattern by re_endp */
+#define REG_NOSPEC 0x1000 /* Maps to PCRE2_LITERAL */
+
+/* This is not used by PCRE2, but by defining it we make it easier
+to slot PCRE2 into existing programs that make POSIX calls. */
+
+#define REG_EXTENDED 0
+
+/* Error values. Not all these are relevant or used by the wrapper. */
+
+enum {
+ REG_ASSERT = 1, /* internal error ? */
+ REG_BADBR, /* invalid repeat counts in {} */
+ REG_BADPAT, /* pattern error */
+ REG_BADRPT, /* ? * + invalid */
+ REG_EBRACE, /* unbalanced {} */
+ REG_EBRACK, /* unbalanced [] */
+ REG_ECOLLATE, /* collation error - not relevant */
+ REG_ECTYPE, /* bad class */
+ REG_EESCAPE, /* bad escape sequence */
+ REG_EMPTY, /* empty expression */
+ REG_EPAREN, /* unbalanced () */
+ REG_ERANGE, /* bad range inside [] */
+ REG_ESIZE, /* expression too big */
+ REG_ESPACE, /* failed to get memory */
+ REG_ESUBREG, /* bad back reference */
+ REG_INVARG, /* bad argument */
+ REG_NOMATCH /* match failed */
+};
+
+
+/* The structure representing a compiled regular expression. It is also used
+for passing the pattern end pointer when REG_PEND is set. */
+
+typedef struct {
+ void *re_pcre2_code;
+ void *re_match_data;
+ const char *re_endp;
+ size_t re_nsub;
+ size_t re_erroffset;
+ int re_cflags;
+} regex_t;
+
+/* The structure in which a captured offset is returned. */
+
+typedef int regoff_t;
+
+typedef struct {
+ regoff_t rm_so;
+ regoff_t rm_eo;
+} regmatch_t;
+
+/* When an application links to a PCRE2 DLL in Windows, the symbols that are
+imported have to be identified as such. When building PCRE2, the appropriate
+export settings are needed, and are set in pcre2posix.c before including this
+file. */
+
+#if defined(_WIN32) && !defined(PCRE2_STATIC) && !defined(PCRE2POSIX_EXP_DECL)
+# define PCRE2POSIX_EXP_DECL extern __declspec(dllimport)
+# define PCRE2POSIX_EXP_DEFN __declspec(dllimport)
+#endif
+
+/* By default, we use the standard "extern" declarations. */
+
+#ifndef PCRE2POSIX_EXP_DECL
+# ifdef __cplusplus
+# define PCRE2POSIX_EXP_DECL extern "C"
+# define PCRE2POSIX_EXP_DEFN extern "C"
+# else
+# define PCRE2POSIX_EXP_DECL extern
+# define PCRE2POSIX_EXP_DEFN extern
+# endif
+#endif
+
+/* The functions */
+
+PCRE2POSIX_EXP_DECL int regcomp(regex_t *, const char *, int);
+PCRE2POSIX_EXP_DECL int regexec(const regex_t *, const char *, size_t,
+ regmatch_t *, int);
+PCRE2POSIX_EXP_DECL size_t regerror(int, const regex_t *, char *, size_t);
+PCRE2POSIX_EXP_DECL void regfree(regex_t *);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+/* End of pcre2posix.h */
diff --git a/test/monniaux/pcre2-10.32/pcre2test.c b/test/monniaux/pcre2-10.32/pcre2test.c
new file mode 100644
index 00000000..10d47469
--- /dev/null
+++ b/test/monniaux/pcre2-10.32/pcre2test.c
@@ -0,0 +1,8791 @@
+/*************************************************
+* PCRE2 testing program *
+*************************************************/
+
+/* PCRE2 is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language. In 2014
+the API was completely revised and '2' was added to the name, because the old
+API, which had lasted for 16 years, could not accommodate new requirements. At
+the same time, this testing program was re-designed because its original
+hacked-up (non-) design had also run out of steam.
+
+ Written by Philip Hazel
+ Original code Copyright (c) 1997-2012 University of Cambridge
+ Rewritten code Copyright (c) 2016-2018 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+
+/* This program supports testing of the 8-bit, 16-bit, and 32-bit PCRE2
+libraries in a single program, though its input and output are always 8-bit.
+It is different from modules such as pcre2_compile.c in the library itself,
+which are compiled separately for each code unit width. If two widths are
+enabled, for example, pcre2_compile.c is compiled twice. In contrast,
+pcre2test.c is compiled only once, and linked with all the enabled libraries.
+Therefore, it must not make use of any of the macros from pcre2.h or
+pcre2_internal.h that depend on PCRE2_CODE_UNIT_WIDTH. It does, however, make
+use of SUPPORT_PCRE2_8, SUPPORT_PCRE2_16, and SUPPORT_PCRE2_32, to ensure that
+it references only the enabled library functions. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <locale.h>
+#include <errno.h>
+
+int fileno(FILE *stream);
+
+#if defined NATIVE_ZOS
+#include "pcrzoscs.h"
+/* That header is not included in the main PCRE2 distribution because other
+apparatus is needed to compile pcre2test for z/OS. The header can be found in
+the special z/OS distribution, which is available from www.zaconsultants.net or
+from www.cbttape.org. */
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* Debugging code enabler */
+
+/* #define DEBUG_SHOW_MALLOC_ADDRESSES */
+
+/* Both libreadline and libedit are optionally supported. The user-supplied
+original patch uses readline/readline.h for libedit, but in at least one system
+it is installed as editline/readline.h, so the configuration code now looks for
+that first, falling back to readline/readline.h. */
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+#if defined(SUPPORT_LIBREADLINE)
+#include <readline/readline.h>
+#include <readline/history.h>
+#else
+#if defined(HAVE_EDITLINE_READLINE_H)
+#include <editline/readline.h>
+#else
+#include <readline/readline.h>
+#endif
+#endif
+#endif
+
+/* Put the test for interactive input into a macro so that it can be changed if
+required for different environments. */
+
+#define INTERACTIVE(f) isatty(fileno(f))
+
+
+/* ---------------------- System-specific definitions ---------------------- */
+
+/* A number of things vary for Windows builds. Originally, pcretest opened its
+input and output without "b"; then I was told that "b" was needed in some
+environments, so it was added for release 5.0 to both the input and output. (It
+makes no difference on Unix-like systems.) Later I was told that it is wrong
+for the input on Windows. I've now abstracted the modes into macros that are
+set here, to make it easier to fiddle with them, and removed "b" from the input
+mode under Windows. The BINARY versions are used when saving/restoring compiled
+patterns. */
+
+#if defined(_WIN32) || defined(WIN32)
+#include <io.h> /* For _setmode() */
+#include <fcntl.h> /* For _O_BINARY */
+#define INPUT_MODE "r"
+#define OUTPUT_MODE "wb"
+#define BINARY_INPUT_MODE "rb"
+#define BINARY_OUTPUT_MODE "wb"
+
+#ifndef isatty
+#define isatty _isatty /* This is what Windows calls them, I'm told, */
+#endif /* though in some environments they seem to */
+ /* be already defined, hence the #ifndefs. */
+#ifndef fileno
+#define fileno _fileno
+#endif
+
+/* A user sent this fix for Borland Builder 5 under Windows. */
+
+#ifdef __BORLANDC__
+#define _setmode(handle, mode) setmode(handle, mode)
+#endif
+
+/* Not Windows */
+
+#else
+#include <sys/time.h> /* These two includes are needed */
+#include <sys/resource.h> /* for setrlimit(). */
+#if defined NATIVE_ZOS /* z/OS uses non-binary I/O */
+#define INPUT_MODE "r"
+#define OUTPUT_MODE "w"
+#define BINARY_INPUT_MODE "rb"
+#define BINARY_OUTPUT_MODE "wb"
+#else
+#define INPUT_MODE "rb"
+#define OUTPUT_MODE "wb"
+#define BINARY_INPUT_MODE "rb"
+#define BINARY_OUTPUT_MODE "wb"
+#endif
+#endif
+
+#ifdef __VMS
+#include <ssdef.h>
+void vms_setsymbol( char *, char *, int );
+#endif
+
+/* VC and older compilers don't support %td or %zu. */
+
+#if defined(_MSC_VER) || !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
+#define PTR_FORM "lu"
+#define SIZ_FORM "lu"
+#define SIZ_CAST (unsigned long int)
+#else
+#define PTR_FORM "td"
+#define SIZ_FORM "zu"
+#define SIZ_CAST
+#endif
+
+/* ------------------End of system-specific definitions -------------------- */
+
+/* Glueing macros that are used in several places below. */
+
+#define glue(a,b) a##b
+#define G(a,b) glue(a,b)
+
+/* Miscellaneous parameters and manifests */
+
+#ifndef CLOCKS_PER_SEC
+#ifdef CLK_TCK
+#define CLOCKS_PER_SEC CLK_TCK
+#else
+#define CLOCKS_PER_SEC 100
+#endif
+#endif
+
+#define CFORE_UNSET UINT32_MAX /* Unset value for startend/cfail/cerror fields */
+#define CONVERT_UNSET UINT32_MAX /* Unset value for convert_type field */
+#define DFA_WS_DIMENSION 1000 /* Size of DFA workspace */
+#define DEFAULT_OVECCOUNT 15 /* Default ovector count */
+#define JUNK_OFFSET 0xdeadbeef /* For initializing ovector */
+#define LOCALESIZE 32 /* Size of locale name */
+#define LOOPREPEAT 500000 /* Default loop count for timing */
+#define MALLOCLISTSIZE 20 /* For remembering mallocs */
+#define PARENS_NEST_DEFAULT 220 /* Default parentheses nest limit */
+#define PATSTACKSIZE 20 /* Pattern stack for save/restore testing */
+#define REPLACE_MODSIZE 100 /* Field for reading 8-bit replacement */
+#define VERSION_SIZE 64 /* Size of buffer for the version strings */
+
+/* Make sure the buffer into which replacement strings are copied is big enough
+to hold them as 32-bit code units. */
+
+#define REPLACE_BUFFSIZE 1024 /* This is a byte value */
+
+/* Execution modes */
+
+#define PCRE8_MODE 8
+#define PCRE16_MODE 16
+#define PCRE32_MODE 32
+
+/* Processing returns */
+
+enum { PR_OK, PR_SKIP, PR_ABEND };
+
+/* The macro PRINTABLE determines whether to print an output character as-is or
+as a hex value when showing compiled patterns. is We use it in cases when the
+locale has not been explicitly changed, so as to get consistent output from
+systems that differ in their output from isprint() even in the "C" locale. */
+
+#ifdef EBCDIC
+#define PRINTABLE(c) ((c) >= 64 && (c) < 255)
+#else
+#define PRINTABLE(c) ((c) >= 32 && (c) < 127)
+#endif
+
+#define PRINTOK(c) ((use_tables != NULL && c < 256)? isprint(c) : PRINTABLE(c))
+
+/* We have to include some of the library source files because we need
+to use some of the macros, internal structure definitions, and other internal
+values - pcre2test has "inside information" compared to an application program
+that strictly follows the PCRE2 API.
+
+Before including pcre2_internal.h we define PRIV so that it does not get
+defined therein. This ensures that PRIV names in the included files do not
+clash with those in the libraries. Also, although pcre2_internal.h does itself
+include pcre2.h, we explicitly include it beforehand, along with pcre2posix.h,
+so that the PCRE2_EXP_xxx macros get set appropriately for an application, not
+for building the library. */
+
+#define PRIV(name) name
+#define PCRE2_CODE_UNIT_WIDTH 0
+#include "pcre2.h"
+#include "pcre2posix.h"
+#include "pcre2_internal.h"
+
+/* We need access to some of the data tables that PCRE2 uses. Defining
+PCRE2_PCRETEST makes some minor changes in the files. The previous definition
+of PRIV avoids name clashes. */
+
+#define PCRE2_PCRE2TEST
+#include "pcre2_tables.c"
+#include "pcre2_ucd.c"
+
+/* 32-bit integer values in the input are read by strtoul() or strtol(). The
+check needed for overflow depends on whether long ints are in fact longer than
+ints. They are defined not to be shorter. */
+
+#if ULONG_MAX > UINT32_MAX
+#define U32OVERFLOW(x) (x > UINT32_MAX)
+#else
+#define U32OVERFLOW(x) (x == UINT32_MAX)
+#endif
+
+#if LONG_MAX > INT32_MAX
+#define S32OVERFLOW(x) (x > INT32_MAX || x < INT32_MIN)
+#else
+#define S32OVERFLOW(x) (x == INT32_MAX || x == INT32_MIN)
+#endif
+
+/* When PCRE2_CODE_UNIT_WIDTH is zero, pcre2_internal.h does not include
+pcre2_intmodedep.h, which is where mode-dependent macros and structures are
+defined. We can now include it for each supported code unit width. Because
+PCRE2_CODE_UNIT_WIDTH was defined as zero before including pcre2.h, it will
+have left PCRE2_SUFFIX defined as a no-op. We must re-define it appropriately
+while including these files, and then restore it to a no-op. Because LINK_SIZE
+may be changed in 16-bit mode and forced to 1 in 32-bit mode, the order of
+these inclusions should not be changed. */
+
+#undef PCRE2_SUFFIX
+#undef PCRE2_CODE_UNIT_WIDTH
+
+#ifdef SUPPORT_PCRE2_8
+#define PCRE2_CODE_UNIT_WIDTH 8
+#define PCRE2_SUFFIX(a) G(a,8)
+#include "pcre2_intmodedep.h"
+#include "pcre2_printint.c"
+#undef PCRE2_CODE_UNIT_WIDTH
+#undef PCRE2_SUFFIX
+#endif /* SUPPORT_PCRE2_8 */
+
+#ifdef SUPPORT_PCRE2_16
+#define PCRE2_CODE_UNIT_WIDTH 16
+#define PCRE2_SUFFIX(a) G(a,16)
+#include "pcre2_intmodedep.h"
+#include "pcre2_printint.c"
+#undef PCRE2_CODE_UNIT_WIDTH
+#undef PCRE2_SUFFIX
+#endif /* SUPPORT_PCRE2_16 */
+
+#ifdef SUPPORT_PCRE2_32
+#define PCRE2_CODE_UNIT_WIDTH 32
+#define PCRE2_SUFFIX(a) G(a,32)
+#include "pcre2_intmodedep.h"
+#include "pcre2_printint.c"
+#undef PCRE2_CODE_UNIT_WIDTH
+#undef PCRE2_SUFFIX
+#endif /* SUPPORT_PCRE2_32 */
+
+#define PCRE2_SUFFIX(a) a
+
+/* We need to be able to check input text for UTF-8 validity, whatever code
+widths are actually available, because the input to pcre2test is always in
+8-bit code units. So we include the UTF validity checking function for 8-bit
+code units. */
+
+extern int valid_utf(PCRE2_SPTR8, PCRE2_SIZE, PCRE2_SIZE *);
+
+#define PCRE2_CODE_UNIT_WIDTH 8
+#undef PCRE2_SPTR
+#define PCRE2_SPTR PCRE2_SPTR8
+#include "pcre2_valid_utf.c"
+#undef PCRE2_CODE_UNIT_WIDTH
+#undef PCRE2_SPTR
+
+/* If we have 8-bit support, default to it; if there is also 16-or 32-bit
+support, it can be selected by a command-line option. If there is no 8-bit
+support, there must be 16-bit or 32-bit support, so default to one of them. The
+config function, JIT stack, contexts, and version string are the same in all
+modes, so use the form of the first that is available. */
+
+#if defined SUPPORT_PCRE2_8
+#define DEFAULT_TEST_MODE PCRE8_MODE
+#define VERSION_TYPE PCRE2_UCHAR8
+#define PCRE2_CONFIG pcre2_config_8
+#define PCRE2_JIT_STACK pcre2_jit_stack_8
+#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_8
+#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_8
+#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_8
+#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_8
+
+#elif defined SUPPORT_PCRE2_16
+#define DEFAULT_TEST_MODE PCRE16_MODE
+#define VERSION_TYPE PCRE2_UCHAR16
+#define PCRE2_CONFIG pcre2_config_16
+#define PCRE2_JIT_STACK pcre2_jit_stack_16
+#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_16
+#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_16
+#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_16
+#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_16
+
+#elif defined SUPPORT_PCRE2_32
+#define DEFAULT_TEST_MODE PCRE32_MODE
+#define VERSION_TYPE PCRE2_UCHAR32
+#define PCRE2_CONFIG pcre2_config_32
+#define PCRE2_JIT_STACK pcre2_jit_stack_32
+#define PCRE2_REAL_GENERAL_CONTEXT pcre2_real_general_context_32
+#define PCRE2_REAL_COMPILE_CONTEXT pcre2_real_compile_context_32
+#define PCRE2_REAL_CONVERT_CONTEXT pcre2_real_convert_context_32
+#define PCRE2_REAL_MATCH_CONTEXT pcre2_real_match_context_32
+#endif
+
+/* ------------- Structure and table for handling #-commands ------------- */
+
+typedef struct cmdstruct {
+ const char *name;
+ int value;
+} cmdstruct;
+
+enum { CMD_FORBID_UTF, CMD_LOAD, CMD_NEWLINE_DEFAULT, CMD_PATTERN,
+ CMD_PERLTEST, CMD_POP, CMD_POPCOPY, CMD_SAVE, CMD_SUBJECT, CMD_UNKNOWN };
+
+static cmdstruct cmdlist[] = {
+ { "forbid_utf", CMD_FORBID_UTF },
+ { "load", CMD_LOAD },
+ { "newline_default", CMD_NEWLINE_DEFAULT },
+ { "pattern", CMD_PATTERN },
+ { "perltest", CMD_PERLTEST },
+ { "pop", CMD_POP },
+ { "popcopy", CMD_POPCOPY },
+ { "save", CMD_SAVE },
+ { "subject", CMD_SUBJECT }};
+
+#define cmdlistcount (sizeof(cmdlist)/sizeof(cmdstruct))
+
+/* ------------- Structures and tables for handling modifiers -------------- */
+
+/* Table of names for newline types. Must be kept in step with the definitions
+of PCRE2_NEWLINE_xx in pcre2.h. */
+
+static const char *newlines[] = {
+ "DEFAULT", "CR", "LF", "CRLF", "ANY", "ANYCRLF", "NUL" };
+
+/* Structure and table for handling pattern conversion types. */
+
+typedef struct convertstruct {
+ const char *name;
+ uint32_t option;
+} convertstruct;
+
+static convertstruct convertlist[] = {
+ { "glob", PCRE2_CONVERT_GLOB },
+ { "glob_no_starstar", PCRE2_CONVERT_GLOB_NO_STARSTAR },
+ { "glob_no_wild_separator", PCRE2_CONVERT_GLOB_NO_WILD_SEPARATOR },
+ { "posix_basic", PCRE2_CONVERT_POSIX_BASIC },
+ { "posix_extended", PCRE2_CONVERT_POSIX_EXTENDED },
+ { "unset", CONVERT_UNSET }};
+
+#define convertlistcount (sizeof(convertlist)/sizeof(convertstruct))
+
+/* Modifier types and applicability */
+
+enum { MOD_CTC, /* Applies to a compile context */
+ MOD_CTM, /* Applies to a match context */
+ MOD_PAT, /* Applies to a pattern */
+ MOD_PATP, /* Ditto, OK for Perl test */
+ MOD_DAT, /* Applies to a data line */
+ MOD_PD, /* Applies to a pattern or a data line */
+ MOD_PDP, /* As MOD_PD, OK for Perl test */
+ MOD_PND, /* As MOD_PD, but not for a default pattern */
+ MOD_PNDP, /* As MOD_PND, OK for Perl test */
+ MOD_CHR, /* Is a single character */
+ MOD_CON, /* Is a "convert" type/options list */
+ MOD_CTL, /* Is a control bit */
+ MOD_BSR, /* Is a BSR value */
+ MOD_IN2, /* Is one or two unsigned integers */
+ MOD_INS, /* Is a signed integer */
+ MOD_INT, /* Is an unsigned integer */
+ MOD_IND, /* Is an unsigned integer, but no value => default */
+ MOD_NL, /* Is a newline value */
+ MOD_NN, /* Is a number or a name; more than one may occur */
+ MOD_OPT, /* Is an option bit */
+ MOD_SIZ, /* Is a PCRE2_SIZE value */
+ MOD_STR }; /* Is a string */
+
+/* Control bits. Some apply to compiling, some to matching, but some can be set
+either on a pattern or a data line, so they must all be distinct. There are now
+so many of them that they are split into two fields. */
+
+#define CTL_AFTERTEXT 0x00000001u
+#define CTL_ALLAFTERTEXT 0x00000002u
+#define CTL_ALLCAPTURES 0x00000004u
+#define CTL_ALLUSEDTEXT 0x00000008u
+#define CTL_ALTGLOBAL 0x00000010u
+#define CTL_BINCODE 0x00000020u
+#define CTL_CALLOUT_CAPTURE 0x00000040u
+#define CTL_CALLOUT_INFO 0x00000080u
+#define CTL_CALLOUT_NONE 0x00000100u
+#define CTL_DFA 0x00000200u
+#define CTL_EXPAND 0x00000400u
+#define CTL_FINDLIMITS 0x00000800u
+#define CTL_FRAMESIZE 0x00001000u
+#define CTL_FULLBINCODE 0x00002000u
+#define CTL_GETALL 0x00004000u
+#define CTL_GLOBAL 0x00008000u
+#define CTL_HEXPAT 0x00010000u /* Same word as USE_LENGTH */
+#define CTL_INFO 0x00020000u
+#define CTL_JITFAST 0x00040000u
+#define CTL_JITVERIFY 0x00080000u
+#define CTL_MARK 0x00100000u
+#define CTL_MEMORY 0x00200000u
+#define CTL_NULLCONTEXT 0x00400000u
+#define CTL_POSIX 0x00800000u
+#define CTL_POSIX_NOSUB 0x01000000u
+#define CTL_PUSH 0x02000000u /* These three must be */
+#define CTL_PUSHCOPY 0x04000000u /* all in the same */
+#define CTL_PUSHTABLESCOPY 0x08000000u /* word. */
+#define CTL_STARTCHAR 0x10000000u
+#define CTL_USE_LENGTH 0x20000000u /* Same word as HEXPAT */
+#define CTL_UTF8_INPUT 0x40000000u
+#define CTL_ZERO_TERMINATE 0x80000000u
+
+/* Combinations */
+
+#define CTL_DEBUG (CTL_FULLBINCODE|CTL_INFO) /* For setting */
+#define CTL_ANYINFO (CTL_DEBUG|CTL_BINCODE|CTL_CALLOUT_INFO)
+#define CTL_ANYGLOB (CTL_ALTGLOBAL|CTL_GLOBAL)
+
+/* Second control word */
+
+#define CTL2_SUBSTITUTE_EXTENDED 0x00000001u
+#define CTL2_SUBSTITUTE_OVERFLOW_LENGTH 0x00000002u
+#define CTL2_SUBSTITUTE_UNKNOWN_UNSET 0x00000004u
+#define CTL2_SUBSTITUTE_UNSET_EMPTY 0x00000008u
+#define CTL2_SUBJECT_LITERAL 0x00000010u
+#define CTL2_CALLOUT_NO_WHERE 0x00000020u
+#define CTL2_CALLOUT_EXTRA 0x00000040u
+
+#define CTL2_NL_SET 0x40000000u /* Informational */
+#define CTL2_BSR_SET 0x80000000u /* Informational */
+
+/* These are the matching controls that may be set either on a pattern or on a
+data line. They are copied from the pattern controls as initial settings for
+data line controls. Note that CTL_MEMORY is not included here, because it does
+different things in the two cases. */
+
+#define CTL_ALLPD (CTL_AFTERTEXT|\
+ CTL_ALLAFTERTEXT|\
+ CTL_ALLCAPTURES|\
+ CTL_ALLUSEDTEXT|\
+ CTL_ALTGLOBAL|\
+ CTL_GLOBAL|\
+ CTL_MARK|\
+ CTL_STARTCHAR|\
+ CTL_UTF8_INPUT)
+
+#define CTL2_ALLPD (CTL2_SUBSTITUTE_EXTENDED|\
+ CTL2_SUBSTITUTE_OVERFLOW_LENGTH|\
+ CTL2_SUBSTITUTE_UNKNOWN_UNSET|\
+ CTL2_SUBSTITUTE_UNSET_EMPTY)
+
+/* Structures for holding modifier information for patterns and subject strings
+(data). Fields containing modifiers that can be set either for a pattern or a
+subject must be at the start and in the same order in both cases so that the
+same offset in the big table below works for both. */
+
+typedef struct patctl { /* Structure for pattern modifiers. */
+ uint32_t options; /* Must be in same position as datctl */
+ uint32_t control; /* Must be in same position as datctl */
+ uint32_t control2; /* Must be in same position as datctl */
+ uint32_t jitstack; /* Must be in same position as datctl */
+ uint8_t replacement[REPLACE_MODSIZE]; /* So must this */
+ uint32_t jit;
+ uint32_t stackguard_test;
+ uint32_t tables_id;
+ uint32_t convert_type;
+ uint32_t convert_length;
+ uint32_t convert_glob_escape;
+ uint32_t convert_glob_separator;
+ uint32_t regerror_buffsize;
+ uint8_t locale[LOCALESIZE];
+} patctl;
+
+#define MAXCPYGET 10
+#define LENCPYGET 64
+
+typedef struct datctl { /* Structure for data line modifiers. */
+ uint32_t options; /* Must be in same position as patctl */
+ uint32_t control; /* Must be in same position as patctl */
+ uint32_t control2; /* Must be in same position as patctl */
+ uint32_t jitstack; /* Must be in same position as patctl */
+ uint8_t replacement[REPLACE_MODSIZE]; /* So must this */
+ uint32_t startend[2];
+ uint32_t cerror[2];
+ uint32_t cfail[2];
+ int32_t callout_data;
+ int32_t copy_numbers[MAXCPYGET];
+ int32_t get_numbers[MAXCPYGET];
+ uint32_t oveccount;
+ uint32_t offset;
+ uint8_t copy_names[LENCPYGET];
+ uint8_t get_names[LENCPYGET];
+} datctl;
+
+/* Ids for which context to modify. */
+
+enum { CTX_PAT, /* Active pattern context */
+ CTX_POPPAT, /* Ditto, for a popped pattern */
+ CTX_DEFPAT, /* Default pattern context */
+ CTX_DAT, /* Active data (match) context */
+ CTX_DEFDAT }; /* Default data (match) context */
+
+/* Macros to simplify the big table below. */
+
+#define CO(name) offsetof(PCRE2_REAL_COMPILE_CONTEXT, name)
+#define MO(name) offsetof(PCRE2_REAL_MATCH_CONTEXT, name)
+#define PO(name) offsetof(patctl, name)
+#define PD(name) PO(name)
+#define DO(name) offsetof(datctl, name)
+
+/* Table of all long-form modifiers. Must be in collating sequence of modifier
+name because it is searched by binary chop. */
+
+typedef struct modstruct {
+ const char *name;
+ uint16_t which;
+ uint16_t type;
+ uint32_t value;
+ PCRE2_SIZE offset;
+} modstruct;
+
+static modstruct modlist[] = {
+ { "aftertext", MOD_PNDP, MOD_CTL, CTL_AFTERTEXT, PO(control) },
+ { "allaftertext", MOD_PNDP, MOD_CTL, CTL_ALLAFTERTEXT, PO(control) },
+ { "allcaptures", MOD_PND, MOD_CTL, CTL_ALLCAPTURES, PO(control) },
+ { "allow_empty_class", MOD_PAT, MOD_OPT, PCRE2_ALLOW_EMPTY_CLASS, PO(options) },
+ { "allow_surrogate_escapes", MOD_CTC, MOD_OPT, PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES, CO(extra_options) },
+ { "allusedtext", MOD_PNDP, MOD_CTL, CTL_ALLUSEDTEXT, PO(control) },
+ { "alt_bsux", MOD_PAT, MOD_OPT, PCRE2_ALT_BSUX, PO(options) },
+ { "alt_circumflex", MOD_PAT, MOD_OPT, PCRE2_ALT_CIRCUMFLEX, PO(options) },
+ { "alt_verbnames", MOD_PAT, MOD_OPT, PCRE2_ALT_VERBNAMES, PO(options) },
+ { "altglobal", MOD_PND, MOD_CTL, CTL_ALTGLOBAL, PO(control) },
+ { "anchored", MOD_PD, MOD_OPT, PCRE2_ANCHORED, PD(options) },
+ { "auto_callout", MOD_PAT, MOD_OPT, PCRE2_AUTO_CALLOUT, PO(options) },
+ { "bad_escape_is_literal", MOD_CTC, MOD_OPT, PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL, CO(extra_options) },
+ { "bincode", MOD_PAT, MOD_CTL, CTL_BINCODE, PO(control) },
+ { "bsr", MOD_CTC, MOD_BSR, 0, CO(bsr_convention) },
+ { "callout_capture", MOD_DAT, MOD_CTL, CTL_CALLOUT_CAPTURE, DO(control) },
+ { "callout_data", MOD_DAT, MOD_INS, 0, DO(callout_data) },
+ { "callout_error", MOD_DAT, MOD_IN2, 0, DO(cerror) },
+ { "callout_extra", MOD_DAT, MOD_CTL, CTL2_CALLOUT_EXTRA, DO(control2) },
+ { "callout_fail", MOD_DAT, MOD_IN2, 0, DO(cfail) },
+ { "callout_info", MOD_PAT, MOD_CTL, CTL_CALLOUT_INFO, PO(control) },
+ { "callout_no_where", MOD_DAT, MOD_CTL, CTL2_CALLOUT_NO_WHERE, DO(control2) },
+ { "callout_none", MOD_DAT, MOD_CTL, CTL_CALLOUT_NONE, DO(control) },
+ { "caseless", MOD_PATP, MOD_OPT, PCRE2_CASELESS, PO(options) },
+ { "convert", MOD_PAT, MOD_CON, 0, PO(convert_type) },
+ { "convert_glob_escape", MOD_PAT, MOD_CHR, 0, PO(convert_glob_escape) },
+ { "convert_glob_separator", MOD_PAT, MOD_CHR, 0, PO(convert_glob_separator) },
+ { "convert_length", MOD_PAT, MOD_INT, 0, PO(convert_length) },
+ { "copy", MOD_DAT, MOD_NN, DO(copy_numbers), DO(copy_names) },
+ { "debug", MOD_PAT, MOD_CTL, CTL_DEBUG, PO(control) },
+ { "depth_limit", MOD_CTM, MOD_INT, 0, MO(depth_limit) },
+ { "dfa", MOD_DAT, MOD_CTL, CTL_DFA, DO(control) },
+ { "dfa_restart", MOD_DAT, MOD_OPT, PCRE2_DFA_RESTART, DO(options) },
+ { "dfa_shortest", MOD_DAT, MOD_OPT, PCRE2_DFA_SHORTEST, DO(options) },
+ { "dollar_endonly", MOD_PAT, MOD_OPT, PCRE2_DOLLAR_ENDONLY, PO(options) },
+ { "dotall", MOD_PATP, MOD_OPT, PCRE2_DOTALL, PO(options) },
+ { "dupnames", MOD_PATP, MOD_OPT, PCRE2_DUPNAMES, PO(options) },
+ { "endanchored", MOD_PD, MOD_OPT, PCRE2_ENDANCHORED, PD(options) },
+ { "expand", MOD_PAT, MOD_CTL, CTL_EXPAND, PO(control) },
+ { "extended", MOD_PATP, MOD_OPT, PCRE2_EXTENDED, PO(options) },
+ { "extended_more", MOD_PATP, MOD_OPT, PCRE2_EXTENDED_MORE, PO(options) },
+ { "find_limits", MOD_DAT, MOD_CTL, CTL_FINDLIMITS, DO(control) },
+ { "firstline", MOD_PAT, MOD_OPT, PCRE2_FIRSTLINE, PO(options) },
+ { "framesize", MOD_PAT, MOD_CTL, CTL_FRAMESIZE, PO(control) },
+ { "fullbincode", MOD_PAT, MOD_CTL, CTL_FULLBINCODE, PO(control) },
+ { "get", MOD_DAT, MOD_NN, DO(get_numbers), DO(get_names) },
+ { "getall", MOD_DAT, MOD_CTL, CTL_GETALL, DO(control) },
+ { "global", MOD_PNDP, MOD_CTL, CTL_GLOBAL, PO(control) },
+ { "heap_limit", MOD_CTM, MOD_INT, 0, MO(heap_limit) },
+ { "hex", MOD_PAT, MOD_CTL, CTL_HEXPAT, PO(control) },
+ { "info", MOD_PAT, MOD_CTL, CTL_INFO, PO(control) },
+ { "jit", MOD_PAT, MOD_IND, 7, PO(jit) },
+ { "jitfast", MOD_PAT, MOD_CTL, CTL_JITFAST, PO(control) },
+ { "jitstack", MOD_PNDP, MOD_INT, 0, PO(jitstack) },
+ { "jitverify", MOD_PAT, MOD_CTL, CTL_JITVERIFY, PO(control) },
+ { "literal", MOD_PAT, MOD_OPT, PCRE2_LITERAL, PO(options) },
+ { "locale", MOD_PAT, MOD_STR, LOCALESIZE, PO(locale) },
+ { "mark", MOD_PNDP, MOD_CTL, CTL_MARK, PO(control) },
+ { "match_limit", MOD_CTM, MOD_INT, 0, MO(match_limit) },
+ { "match_line", MOD_CTC, MOD_OPT, PCRE2_EXTRA_MATCH_LINE, CO(extra_options) },
+ { "match_unset_backref", MOD_PAT, MOD_OPT, PCRE2_MATCH_UNSET_BACKREF, PO(options) },
+ { "match_word", MOD_CTC, MOD_OPT, PCRE2_EXTRA_MATCH_WORD, CO(extra_options) },
+ { "max_pattern_length", MOD_CTC, MOD_SIZ, 0, CO(max_pattern_length) },
+ { "memory", MOD_PD, MOD_CTL, CTL_MEMORY, PD(control) },
+ { "multiline", MOD_PATP, MOD_OPT, PCRE2_MULTILINE, PO(options) },
+ { "never_backslash_c", MOD_PAT, MOD_OPT, PCRE2_NEVER_BACKSLASH_C, PO(options) },
+ { "never_ucp", MOD_PAT, MOD_OPT, PCRE2_NEVER_UCP, PO(options) },
+ { "never_utf", MOD_PAT, MOD_OPT, PCRE2_NEVER_UTF, PO(options) },
+ { "newline", MOD_CTC, MOD_NL, 0, CO(newline_convention) },
+ { "no_auto_capture", MOD_PAT, MOD_OPT, PCRE2_NO_AUTO_CAPTURE, PO(options) },
+ { "no_auto_possess", MOD_PATP, MOD_OPT, PCRE2_NO_AUTO_POSSESS, PO(options) },
+ { "no_dotstar_anchor", MOD_PAT, MOD_OPT, PCRE2_NO_DOTSTAR_ANCHOR, PO(options) },
+ { "no_jit", MOD_DAT, MOD_OPT, PCRE2_NO_JIT, DO(options) },
+ { "no_start_optimize", MOD_PATP, MOD_OPT, PCRE2_NO_START_OPTIMIZE, PO(options) },
+ { "no_utf_check", MOD_PD, MOD_OPT, PCRE2_NO_UTF_CHECK, PD(options) },
+ { "notbol", MOD_DAT, MOD_OPT, PCRE2_NOTBOL, DO(options) },
+ { "notempty", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY, DO(options) },
+ { "notempty_atstart", MOD_DAT, MOD_OPT, PCRE2_NOTEMPTY_ATSTART, DO(options) },
+ { "noteol", MOD_DAT, MOD_OPT, PCRE2_NOTEOL, DO(options) },
+ { "null_context", MOD_PD, MOD_CTL, CTL_NULLCONTEXT, PO(control) },
+ { "offset", MOD_DAT, MOD_INT, 0, DO(offset) },
+ { "offset_limit", MOD_CTM, MOD_SIZ, 0, MO(offset_limit)},
+ { "ovector", MOD_DAT, MOD_INT, 0, DO(oveccount) },
+ { "parens_nest_limit", MOD_CTC, MOD_INT, 0, CO(parens_nest_limit) },
+ { "partial_hard", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) },
+ { "partial_soft", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) },
+ { "ph", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_HARD, DO(options) },
+ { "posix", MOD_PAT, MOD_CTL, CTL_POSIX, PO(control) },
+ { "posix_nosub", MOD_PAT, MOD_CTL, CTL_POSIX|CTL_POSIX_NOSUB, PO(control) },
+ { "posix_startend", MOD_DAT, MOD_IN2, 0, DO(startend) },
+ { "ps", MOD_DAT, MOD_OPT, PCRE2_PARTIAL_SOFT, DO(options) },
+ { "push", MOD_PAT, MOD_CTL, CTL_PUSH, PO(control) },
+ { "pushcopy", MOD_PAT, MOD_CTL, CTL_PUSHCOPY, PO(control) },
+ { "pushtablescopy", MOD_PAT, MOD_CTL, CTL_PUSHTABLESCOPY, PO(control) },
+ { "recursion_limit", MOD_CTM, MOD_INT, 0, MO(depth_limit) }, /* Obsolete synonym */
+ { "regerror_buffsize", MOD_PAT, MOD_INT, 0, PO(regerror_buffsize) },
+ { "replace", MOD_PND, MOD_STR, REPLACE_MODSIZE, PO(replacement) },
+ { "stackguard", MOD_PAT, MOD_INT, 0, PO(stackguard_test) },
+ { "startchar", MOD_PND, MOD_CTL, CTL_STARTCHAR, PO(control) },
+ { "startoffset", MOD_DAT, MOD_INT, 0, DO(offset) },
+ { "subject_literal", MOD_PATP, MOD_CTL, CTL2_SUBJECT_LITERAL, PO(control2) },
+ { "substitute_extended", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_EXTENDED, PO(control2) },
+ { "substitute_overflow_length", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_OVERFLOW_LENGTH, PO(control2) },
+ { "substitute_unknown_unset", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_UNKNOWN_UNSET, PO(control2) },
+ { "substitute_unset_empty", MOD_PND, MOD_CTL, CTL2_SUBSTITUTE_UNSET_EMPTY, PO(control2) },
+ { "tables", MOD_PAT, MOD_INT, 0, PO(tables_id) },
+ { "ucp", MOD_PATP, MOD_OPT, PCRE2_UCP, PO(options) },
+ { "ungreedy", MOD_PAT, MOD_OPT, PCRE2_UNGREEDY, PO(options) },
+ { "use_length", MOD_PAT, MOD_CTL, CTL_USE_LENGTH, PO(control) },
+ { "use_offset_limit", MOD_PAT, MOD_OPT, PCRE2_USE_OFFSET_LIMIT, PO(options) },
+ { "utf", MOD_PATP, MOD_OPT, PCRE2_UTF, PO(options) },
+ { "utf8_input", MOD_PAT, MOD_CTL, CTL_UTF8_INPUT, PO(control) },
+ { "zero_terminate", MOD_DAT, MOD_CTL, CTL_ZERO_TERMINATE, DO(control) }
+};
+
+#define MODLISTCOUNT sizeof(modlist)/sizeof(modstruct)
+
+/* Controls and options that are supported for use with the POSIX interface. */
+
+#define POSIX_SUPPORTED_COMPILE_OPTIONS ( \
+ PCRE2_CASELESS|PCRE2_DOTALL|PCRE2_LITERAL|PCRE2_MULTILINE|PCRE2_UCP| \
+ PCRE2_UTF|PCRE2_UNGREEDY)
+
+#define POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS (0)
+
+#define POSIX_SUPPORTED_COMPILE_CONTROLS ( \
+ CTL_AFTERTEXT|CTL_ALLAFTERTEXT|CTL_EXPAND|CTL_HEXPAT|CTL_POSIX| \
+ CTL_POSIX_NOSUB|CTL_USE_LENGTH)
+
+#define POSIX_SUPPORTED_COMPILE_CONTROLS2 (0)
+
+#define POSIX_SUPPORTED_MATCH_OPTIONS ( \
+ PCRE2_NOTBOL|PCRE2_NOTEMPTY|PCRE2_NOTEOL)
+
+#define POSIX_SUPPORTED_MATCH_CONTROLS (CTL_AFTERTEXT|CTL_ALLAFTERTEXT)
+#define POSIX_SUPPORTED_MATCH_CONTROLS2 (0)
+
+/* Control bits that are not ignored with 'push'. */
+
+#define PUSH_SUPPORTED_COMPILE_CONTROLS ( \
+ CTL_BINCODE|CTL_CALLOUT_INFO|CTL_FULLBINCODE|CTL_HEXPAT|CTL_INFO| \
+ CTL_JITVERIFY|CTL_MEMORY|CTL_FRAMESIZE|CTL_PUSH|CTL_PUSHCOPY| \
+ CTL_PUSHTABLESCOPY|CTL_USE_LENGTH)
+
+#define PUSH_SUPPORTED_COMPILE_CONTROLS2 (CTL2_BSR_SET|CTL2_NL_SET)
+
+/* Controls that apply only at compile time with 'push'. */
+
+#define PUSH_COMPILE_ONLY_CONTROLS CTL_JITVERIFY
+#define PUSH_COMPILE_ONLY_CONTROLS2 (0)
+
+/* Controls that are forbidden with #pop or #popcopy. */
+
+#define NOTPOP_CONTROLS (CTL_HEXPAT|CTL_POSIX|CTL_POSIX_NOSUB|CTL_PUSH| \
+ CTL_PUSHCOPY|CTL_PUSHTABLESCOPY|CTL_USE_LENGTH)
+
+/* Pattern controls that are mutually exclusive. At present these are all in
+the first control word. Note that CTL_POSIX_NOSUB is always accompanied by
+CTL_POSIX, so it doesn't need its own entries. */
+
+static uint32_t exclusive_pat_controls[] = {
+ CTL_POSIX | CTL_PUSH,
+ CTL_POSIX | CTL_PUSHCOPY,
+ CTL_POSIX | CTL_PUSHTABLESCOPY,
+ CTL_PUSH | CTL_PUSHCOPY,
+ CTL_PUSH | CTL_PUSHTABLESCOPY,
+ CTL_PUSHCOPY | CTL_PUSHTABLESCOPY,
+ CTL_EXPAND | CTL_HEXPAT };
+
+/* Data controls that are mutually exclusive. At present these are all in the
+first control word. */
+
+static uint32_t exclusive_dat_controls[] = {
+ CTL_ALLUSEDTEXT | CTL_STARTCHAR,
+ CTL_FINDLIMITS | CTL_NULLCONTEXT };
+
+/* Table of single-character abbreviated modifiers. The index field is
+initialized to -1, but the first time the modifier is encountered, it is filled
+in with the index of the full entry in modlist, to save repeated searching when
+processing multiple test items. This short list is searched serially, so its
+order does not matter. */
+
+typedef struct c1modstruct {
+ const char *fullname;
+ uint32_t onechar;
+ int index;
+} c1modstruct;
+
+static c1modstruct c1modlist[] = {
+ { "bincode", 'B', -1 },
+ { "info", 'I', -1 },
+ { "global", 'g', -1 },
+ { "caseless", 'i', -1 },
+ { "multiline", 'm', -1 },
+ { "no_auto_capture", 'n', -1 },
+ { "dotall", 's', -1 },
+ { "extended", 'x', -1 }
+};
+
+#define C1MODLISTCOUNT sizeof(c1modlist)/sizeof(c1modstruct)
+
+/* Table of arguments for the -C command line option. Use macros to make the
+table itself easier to read. */
+
+#if defined SUPPORT_PCRE2_8
+#define SUPPORT_8 1
+#endif
+#if defined SUPPORT_PCRE2_16
+#define SUPPORT_16 1
+#endif
+#if defined SUPPORT_PCRE2_32
+#define SUPPORT_32 1
+#endif
+
+#ifndef SUPPORT_8
+#define SUPPORT_8 0
+#endif
+#ifndef SUPPORT_16
+#define SUPPORT_16 0
+#endif
+#ifndef SUPPORT_32
+#define SUPPORT_32 0
+#endif
+
+#ifdef EBCDIC
+#define SUPPORT_EBCDIC 1
+#define EBCDIC_NL CHAR_LF
+#else
+#define SUPPORT_EBCDIC 0
+#define EBCDIC_NL 0
+#endif
+
+#ifdef NEVER_BACKSLASH_C
+#define BACKSLASH_C 0
+#else
+#define BACKSLASH_C 1
+#endif
+
+typedef struct coptstruct {
+ const char *name;
+ uint32_t type;
+ uint32_t value;
+} coptstruct;
+
+enum { CONF_BSR,
+ CONF_FIX,
+ CONF_FIZ,
+ CONF_INT,
+ CONF_NL
+};
+
+static coptstruct coptlist[] = {
+ { "backslash-C", CONF_FIX, BACKSLASH_C },
+ { "bsr", CONF_BSR, PCRE2_CONFIG_BSR },
+ { "ebcdic", CONF_FIX, SUPPORT_EBCDIC },
+ { "ebcdic-nl", CONF_FIZ, EBCDIC_NL },
+ { "jit", CONF_INT, PCRE2_CONFIG_JIT },
+ { "linksize", CONF_INT, PCRE2_CONFIG_LINKSIZE },
+ { "newline", CONF_NL, PCRE2_CONFIG_NEWLINE },
+ { "pcre2-16", CONF_FIX, SUPPORT_16 },
+ { "pcre2-32", CONF_FIX, SUPPORT_32 },
+ { "pcre2-8", CONF_FIX, SUPPORT_8 },
+ { "unicode", CONF_INT, PCRE2_CONFIG_UNICODE }
+};
+
+#define COPTLISTCOUNT sizeof(coptlist)/sizeof(coptstruct)
+
+#undef SUPPORT_8
+#undef SUPPORT_16
+#undef SUPPORT_32
+#undef SUPPORT_EBCDIC
+
+
+/* ----------------------- Static variables ------------------------ */
+
+static FILE *infile;
+static FILE *outfile;
+
+static const void *last_callout_mark;
+static PCRE2_JIT_STACK *jit_stack = NULL;
+static size_t jit_stack_size = 0;
+
+static BOOL first_callout;
+static BOOL jit_was_used;
+static BOOL restrict_for_perl_test = FALSE;
+static BOOL show_memory = FALSE;
+
+static int code_unit_size; /* Bytes */
+static int jitrc; /* Return from JIT compile */
+static int test_mode = DEFAULT_TEST_MODE;
+static int timeit = 0;
+static int timeitm = 0;
+
+clock_t total_compile_time = 0;
+clock_t total_jit_compile_time = 0;
+clock_t total_match_time = 0;
+
+static uint32_t dfa_matched;
+static uint32_t forbid_utf = 0;
+static uint32_t maxlookbehind;
+static uint32_t max_oveccount;
+static uint32_t callout_count;
+
+static uint16_t local_newline_default = 0;
+
+static VERSION_TYPE jittarget[VERSION_SIZE];
+static VERSION_TYPE version[VERSION_SIZE];
+static VERSION_TYPE uversion[VERSION_SIZE];
+
+static patctl def_patctl;
+static patctl pat_patctl;
+static datctl def_datctl;
+static datctl dat_datctl;
+
+static void *patstack[PATSTACKSIZE];
+static int patstacknext = 0;
+
+static void *malloclist[MALLOCLISTSIZE];
+static PCRE2_SIZE malloclistlength[MALLOCLISTSIZE];
+static uint32_t malloclistptr = 0;
+
+#ifdef SUPPORT_PCRE2_8
+static regex_t preg = { NULL, NULL, 0, 0, 0, 0 };
+#endif
+
+static int *dfa_workspace = NULL;
+static const uint8_t *locale_tables = NULL;
+static const uint8_t *use_tables = NULL;
+static uint8_t locale_name[32];
+
+/* We need buffers for building 16/32-bit strings; 8-bit strings don't need
+rebuilding, but set up the same naming scheme for use in macros. The "buffer"
+buffer is where all input lines are read. Its size is the same as pbuffer8.
+Pattern lines are always copied to pbuffer8 for use in callouts, even if they
+are actually compiled from pbuffer16 or pbuffer32. */
+
+static size_t pbuffer8_size = 50000; /* Initial size, bytes */
+static uint8_t *pbuffer8 = NULL;
+static uint8_t *buffer = NULL;
+
+/* The dbuffer is where all processed data lines are put. In non-8-bit modes it
+is cast as needed. For long data lines it grows as necessary. */
+
+static size_t dbuffer_size = 1u << 14; /* Initial size, bytes */
+static uint8_t *dbuffer = NULL;
+
+
+/* ---------------- Mode-dependent variables -------------------*/
+
+#ifdef SUPPORT_PCRE2_8
+static pcre2_code_8 *compiled_code8;
+static pcre2_general_context_8 *general_context8, *general_context_copy8;
+static pcre2_compile_context_8 *pat_context8, *default_pat_context8;
+static pcre2_convert_context_8 *con_context8, *default_con_context8;
+static pcre2_match_context_8 *dat_context8, *default_dat_context8;
+static pcre2_match_data_8 *match_data8;
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+static pcre2_code_16 *compiled_code16;
+static pcre2_general_context_16 *general_context16, *general_context_copy16;
+static pcre2_compile_context_16 *pat_context16, *default_pat_context16;
+static pcre2_convert_context_16 *con_context16, *default_con_context16;
+static pcre2_match_context_16 *dat_context16, *default_dat_context16;
+static pcre2_match_data_16 *match_data16;
+static PCRE2_SIZE pbuffer16_size = 0; /* Set only when needed */
+static uint16_t *pbuffer16 = NULL;
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+static pcre2_code_32 *compiled_code32;
+static pcre2_general_context_32 *general_context32, *general_context_copy32;
+static pcre2_compile_context_32 *pat_context32, *default_pat_context32;
+static pcre2_convert_context_32 *con_context32, *default_con_context32;
+static pcre2_match_context_32 *dat_context32, *default_dat_context32;
+static pcre2_match_data_32 *match_data32;
+static PCRE2_SIZE pbuffer32_size = 0; /* Set only when needed */
+static uint32_t *pbuffer32 = NULL;
+#endif
+
+
+/* ---------------- Macros that work in all modes ----------------- */
+
+#define CAST8VAR(x) CASTVAR(uint8_t *, x)
+#define SET(x,y) SETOP(x,y,=)
+#define SETPLUS(x,y) SETOP(x,y,+=)
+#define strlen8(x) strlen((char *)x)
+
+
+/* ---------------- Mode-dependent, runtime-testing macros ------------------*/
+
+/* Define macros for variables and functions that must be selected dynamically
+depending on the mode setting (8, 16, 32). These are dependent on which modes
+are supported. */
+
+#if (defined (SUPPORT_PCRE2_8) + defined (SUPPORT_PCRE2_16) + \
+ defined (SUPPORT_PCRE2_32)) >= 2
+
+/* ----- All three modes supported ----- */
+
+#if defined(SUPPORT_PCRE2_8) && defined(SUPPORT_PCRE2_16) && defined(SUPPORT_PCRE2_32)
+
+#define CASTFLD(t,a,b) ((test_mode == PCRE8_MODE)? (t)(G(a,8)->b) : \
+ (test_mode == PCRE16_MODE)? (t)(G(a,16)->b) : (t)(G(a,32)->b))
+
+#define CASTVAR(t,x) ( \
+ (test_mode == PCRE8_MODE)? (t)G(x,8) : \
+ (test_mode == PCRE16_MODE)? (t)G(x,16) : (t)G(x,32))
+
+#define CODE_UNIT(a,b) ( \
+ (test_mode == PCRE8_MODE)? (uint32_t)(((PCRE2_SPTR8)(a))[b]) : \
+ (test_mode == PCRE16_MODE)? (uint32_t)(((PCRE2_SPTR16)(a))[b]) : \
+ (uint32_t)(((PCRE2_SPTR32)(a))[b]))
+
+#define CONCTXCPY(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ memcpy(G(a,8),G(b,8),sizeof(pcre2_convert_context_8)); \
+ else if (test_mode == PCRE16_MODE) \
+ memcpy(G(a,16),G(b,16),sizeof(pcre2_convert_context_16)); \
+ else memcpy(G(a,32),G(b,32),sizeof(pcre2_convert_context_32))
+
+#define CONVERT_COPY(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ memcpy(G(a,8),(char *)b,c); \
+ else if (test_mode == PCRE16_MODE) \
+ memcpy(G(a,16),(char *)b,(c)*2); \
+ else if (test_mode == PCRE32_MODE) \
+ memcpy(G(a,32),(char *)b,(c)*4)
+
+#define DATCTXCPY(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ memcpy(G(a,8),G(b,8),sizeof(pcre2_match_context_8)); \
+ else if (test_mode == PCRE16_MODE) \
+ memcpy(G(a,16),G(b,16),sizeof(pcre2_match_context_16)); \
+ else memcpy(G(a,32),G(b,32),sizeof(pcre2_match_context_32))
+
+#define FLD(a,b) ((test_mode == PCRE8_MODE)? G(a,8)->b : \
+ (test_mode == PCRE16_MODE)? G(a,16)->b : G(a,32)->b)
+
+#define PATCTXCPY(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ memcpy(G(a,8),G(b,8),sizeof(pcre2_compile_context_8)); \
+ else if (test_mode == PCRE16_MODE) \
+ memcpy(G(a,16),G(b,16),sizeof(pcre2_compile_context_16)); \
+ else memcpy(G(a,32),G(b,32),sizeof(pcre2_compile_context_32))
+
+#define PCHARS(lv, p, offset, len, utf, f) \
+ if (test_mode == PCRE32_MODE) \
+ lv = pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f); \
+ else if (test_mode == PCRE16_MODE) \
+ lv = pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f); \
+ else \
+ lv = pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+
+#define PCHARSV(p, offset, len, utf, f) \
+ if (test_mode == PCRE32_MODE) \
+ (void)pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f); \
+ else if (test_mode == PCRE16_MODE) \
+ (void)pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f); \
+ else \
+ (void)pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_callout_enumerate_8(compiled_code8, \
+ (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_callout_enumerate_16(compiled_code16, \
+ (int(*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c); \
+ else \
+ a = pcre2_callout_enumerate_32(compiled_code32, \
+ (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c)
+
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ G(a,8) = pcre2_code_copy_8(b); \
+ else if (test_mode == PCRE16_MODE) \
+ G(a,16) = pcre2_code_copy_16(b); \
+ else \
+ G(a,32) = pcre2_code_copy_32(b)
+
+#define PCRE2_CODE_COPY_TO_VOID(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ a = (void *)pcre2_code_copy_8(G(b,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ a = (void *)pcre2_code_copy_16(G(b,16)); \
+ else \
+ a = (void *)pcre2_code_copy_32(G(b,32))
+
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ a = (void *)pcre2_code_copy_with_tables_8(G(b,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ a = (void *)pcre2_code_copy_with_tables_16(G(b,16)); \
+ else \
+ a = (void *)pcre2_code_copy_with_tables_32(G(b,32))
+
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+ if (test_mode == PCRE8_MODE) \
+ G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g); \
+ else if (test_mode == PCRE16_MODE) \
+ G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g); \
+ else \
+ G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g)
+
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+ if (test_mode == PCRE8_MODE) pcre2_converted_pattern_free_8((PCRE2_UCHAR8 *)a); \
+ else if (test_mode == PCRE16_MODE) pcre2_converted_pattern_free_16((PCRE2_UCHAR16 *)a); \
+ else pcre2_converted_pattern_free_32((PCRE2_UCHAR32 *)a)
+
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h,i,j); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h,i,j); \
+ else \
+ a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h,i,j)
+
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+ if (test_mode == PCRE8_MODE) \
+ r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size)); \
+ else if (test_mode == PCRE16_MODE) \
+ r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size/2)); \
+ else \
+ r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size/4))
+
+#define PCRE2_GET_OVECTOR_COUNT(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_get_ovector_count_8(G(b,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_get_ovector_count_16(G(b,16)); \
+ else \
+ a = pcre2_get_ovector_count_32(G(b,32))
+
+#define PCRE2_GET_STARTCHAR(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_get_startchar_8(G(b,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_get_startchar_16(G(b,16)); \
+ else \
+ a = pcre2_get_startchar_32(G(b,32))
+
+#define PCRE2_JIT_COMPILE(r,a,b) \
+ if (test_mode == PCRE8_MODE) r = pcre2_jit_compile_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) r = pcre2_jit_compile_16(G(a,16),b); \
+ else r = pcre2_jit_compile_32(G(a,32),b)
+
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \
+ if (test_mode == PCRE8_MODE) pcre2_jit_free_unused_memory_8(G(a,8)); \
+ else if (test_mode == PCRE16_MODE) pcre2_jit_free_unused_memory_16(G(a,16)); \
+ else pcre2_jit_free_unused_memory_32(G(a,32))
+
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_jit_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_jit_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h); \
+ else \
+ a = pcre2_jit_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+ if (test_mode == PCRE8_MODE) \
+ a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_8(b,c,d); \
+ else if (test_mode == PCRE16_MODE) \
+ a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_16(b,c,d); \
+ else \
+ a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_32(b,c,d);
+
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_jit_stack_assign_8(G(a,8),(pcre2_jit_callback_8)b,c); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_jit_stack_assign_16(G(a,16),(pcre2_jit_callback_16)b,c); \
+ else \
+ pcre2_jit_stack_assign_32(G(a,32),(pcre2_jit_callback_32)b,c);
+
+#define PCRE2_JIT_STACK_FREE(a) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_jit_stack_free_8((pcre2_jit_stack_8 *)a); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_jit_stack_free_16((pcre2_jit_stack_16 *)a); \
+ else \
+ pcre2_jit_stack_free_32((pcre2_jit_stack_32 *)a);
+
+#define PCRE2_MAKETABLES(a) \
+ if (test_mode == PCRE8_MODE) a = pcre2_maketables_8(NULL); \
+ else if (test_mode == PCRE16_MODE) a = pcre2_maketables_16(NULL); \
+ else a = pcre2_maketables_32(NULL)
+
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h); \
+ else \
+ a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ G(a,8) = pcre2_match_data_create_8(b,c); \
+ else if (test_mode == PCRE16_MODE) \
+ G(a,16) = pcre2_match_data_create_16(b,c); \
+ else \
+ G(a,32) = pcre2_match_data_create_32(b,c)
+
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c); \
+ else if (test_mode == PCRE16_MODE) \
+ G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c); \
+ else \
+ G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c)
+
+#define PCRE2_MATCH_DATA_FREE(a) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_match_data_free_8(G(a,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_match_data_free_16(G(a,16)); \
+ else \
+ pcre2_match_data_free_32(G(a,32))
+
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_pattern_convert_8(G(b,8),c,d,(PCRE2_UCHAR8 **)e,f,G(g,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_pattern_convert_16(G(b,16),c,d,(PCRE2_UCHAR16 **)e,f,G(g,16)); \
+ else \
+ a = pcre2_pattern_convert_32(G(b,32),c,d,(PCRE2_UCHAR32 **)e,f,G(g,32))
+
+#define PCRE2_PATTERN_INFO(a,b,c,d) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_pattern_info_8(G(b,8),c,d); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_pattern_info_16(G(b,16),c,d); \
+ else \
+ a = pcre2_pattern_info_32(G(b,32),c,d)
+
+#define PCRE2_PRINTINT(a) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_printint_8(compiled_code8,outfile,a); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_printint_16(compiled_code16,outfile,a); \
+ else \
+ pcre2_printint_32(compiled_code32,outfile,a)
+
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+ if (test_mode == PCRE8_MODE) \
+ r = pcre2_serialize_decode_8((pcre2_code_8 **)a,b,c,G(d,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ r = pcre2_serialize_decode_16((pcre2_code_16 **)a,b,c,G(d,16)); \
+ else \
+ r = pcre2_serialize_decode_32((pcre2_code_32 **)a,b,c,G(d,32))
+
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+ if (test_mode == PCRE8_MODE) \
+ r = pcre2_serialize_encode_8((const pcre2_code_8 **)a,b,c,d,G(e,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ r = pcre2_serialize_encode_16((const pcre2_code_16 **)a,b,c,d,G(e,16)); \
+ else \
+ r = pcre2_serialize_encode_32((const pcre2_code_32 **)a,b,c,d,G(e,32))
+
+#define PCRE2_SERIALIZE_FREE(a) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_serialize_free_8(a); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_serialize_free_16(a); \
+ else \
+ pcre2_serialize_free_32(a)
+
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+ if (test_mode == PCRE8_MODE) \
+ r = pcre2_serialize_get_number_of_codes_8(a); \
+ else if (test_mode == PCRE16_MODE) \
+ r = pcre2_serialize_get_number_of_codes_16(a); \
+ else \
+ r = pcre2_serialize_get_number_of_codes_32(a); \
+
+#define PCRE2_SET_CALLOUT(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_callout_8(G(a,8),(int (*)(pcre2_callout_block_8 *, void *))b,c); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_callout_16(G(a,16),(int (*)(pcre2_callout_block_16 *, void *))b,c); \
+ else \
+ pcre2_set_callout_32(G(a,32),(int (*)(pcre2_callout_block_32 *, void *))b,c);
+
+#define PCRE2_SET_CHARACTER_TABLES(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_character_tables_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_character_tables_16(G(a,16),b); \
+ else \
+ pcre2_set_character_tables_32(G(a,32),b)
+
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_compile_recursion_guard_8(G(a,8),b,c); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_compile_recursion_guard_16(G(a,16),b,c); \
+ else \
+ pcre2_set_compile_recursion_guard_32(G(a,32),b,c)
+
+#define PCRE2_SET_DEPTH_LIMIT(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_depth_limit_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_depth_limit_16(G(a,16),b); \
+ else \
+ pcre2_set_depth_limit_32(G(a,32),b)
+
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) \
+ if (test_mode == PCRE8_MODE) \
+ r = pcre2_set_glob_separator_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ r = pcre2_set_glob_separator_16(G(a,16),b); \
+ else \
+ r = pcre2_set_glob_separator_32(G(a,32),b)
+
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) \
+ if (test_mode == PCRE8_MODE) \
+ r = pcre2_set_glob_escape_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ r = pcre2_set_glob_escape_16(G(a,16),b); \
+ else \
+ r = pcre2_set_glob_escape_32(G(a,32),b)
+
+#define PCRE2_SET_HEAP_LIMIT(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_heap_limit_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_heap_limit_16(G(a,16),b); \
+ else \
+ pcre2_set_heap_limit_32(G(a,32),b)
+
+#define PCRE2_SET_MATCH_LIMIT(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_match_limit_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_match_limit_16(G(a,16),b); \
+ else \
+ pcre2_set_match_limit_32(G(a,32),b)
+
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_max_pattern_length_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_max_pattern_length_16(G(a,16),b); \
+ else \
+ pcre2_set_max_pattern_length_32(G(a,32),b)
+
+#define PCRE2_SET_OFFSET_LIMIT(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_offset_limit_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_offset_limit_16(G(a,16),b); \
+ else \
+ pcre2_set_offset_limit_32(G(a,32),b)
+
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_set_parens_nest_limit_8(G(a,8),b); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_set_parens_nest_limit_16(G(a,16),b); \
+ else \
+ pcre2_set_parens_nest_limit_32(G(a,32),b)
+
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substitute_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),G(h,8), \
+ (PCRE2_SPTR8)i,j,(PCRE2_UCHAR8 *)k,l); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substitute_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),G(h,16), \
+ (PCRE2_SPTR16)i,j,(PCRE2_UCHAR16 *)k,l); \
+ else \
+ a = pcre2_substitute_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),G(h,32), \
+ (PCRE2_SPTR32)i,j,(PCRE2_UCHAR32 *)k,l)
+
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e); \
+ else \
+ a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e)
+
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_copy_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 *)d,e); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_copy_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 *)d,e); \
+ else \
+ a = pcre2_substring_copy_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 *)d,e)
+
+#define PCRE2_SUBSTRING_FREE(a) \
+ if (test_mode == PCRE8_MODE) pcre2_substring_free_8((PCRE2_UCHAR8 *)a); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_substring_free_16((PCRE2_UCHAR16 *)a); \
+ else pcre2_substring_free_32((PCRE2_UCHAR32 *)a)
+
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e); \
+ else \
+ a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e)
+
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e); \
+ else \
+ a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d); \
+ else \
+ a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_length_bynumber_8(G(b,8),c,d); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_length_bynumber_16(G(b,16),c,d); \
+ else \
+ a = pcre2_substring_length_bynumber_32(G(b,32),c,d)
+
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d); \
+ else \
+ a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d)
+
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+ if (test_mode == PCRE8_MODE) \
+ pcre2_substring_list_free_8((PCRE2_SPTR8 *)a); \
+ else if (test_mode == PCRE16_MODE) \
+ pcre2_substring_list_free_16((PCRE2_SPTR16 *)a); \
+ else \
+ pcre2_substring_list_free_32((PCRE2_SPTR32 *)a)
+
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+ if (test_mode == PCRE8_MODE) \
+ a = pcre2_substring_number_from_name_8(G(b,8),G(c,8)); \
+ else if (test_mode == PCRE16_MODE) \
+ a = pcre2_substring_number_from_name_16(G(b,16),G(c,16)); \
+ else \
+ a = pcre2_substring_number_from_name_32(G(b,32),G(c,32))
+
+#define PTR(x) ( \
+ (test_mode == PCRE8_MODE)? (void *)G(x,8) : \
+ (test_mode == PCRE16_MODE)? (void *)G(x,16) : \
+ (void *)G(x,32))
+
+#define SETFLD(x,y,z) \
+ if (test_mode == PCRE8_MODE) G(x,8)->y = z; \
+ else if (test_mode == PCRE16_MODE) G(x,16)->y = z; \
+ else G(x,32)->y = z
+
+#define SETFLDVEC(x,y,v,z) \
+ if (test_mode == PCRE8_MODE) G(x,8)->y[v] = z; \
+ else if (test_mode == PCRE16_MODE) G(x,16)->y[v] = z; \
+ else G(x,32)->y[v] = z
+
+#define SETOP(x,y,z) \
+ if (test_mode == PCRE8_MODE) G(x,8) z y; \
+ else if (test_mode == PCRE16_MODE) G(x,16) z y; \
+ else G(x,32) z y
+
+#define SETCASTPTR(x,y) \
+ if (test_mode == PCRE8_MODE) \
+ G(x,8) = (uint8_t *)(y); \
+ else if (test_mode == PCRE16_MODE) \
+ G(x,16) = (uint16_t *)(y); \
+ else \
+ G(x,32) = (uint32_t *)(y)
+
+#define STRLEN(p) ((test_mode == PCRE8_MODE)? ((int)strlen((char *)p)) : \
+ (test_mode == PCRE16_MODE)? ((int)strlen16((PCRE2_SPTR16)p)) : \
+ ((int)strlen32((PCRE2_SPTR32)p)))
+
+#define SUB1(a,b) \
+ if (test_mode == PCRE8_MODE) G(a,8)(G(b,8)); \
+ else if (test_mode == PCRE16_MODE) G(a,16)(G(b,16)); \
+ else G(a,32)(G(b,32))
+
+#define SUB2(a,b,c) \
+ if (test_mode == PCRE8_MODE) G(a,8)(G(b,8),G(c,8)); \
+ else if (test_mode == PCRE16_MODE) G(a,16)(G(b,16),G(c,16)); \
+ else G(a,32)(G(b,32),G(c,32))
+
+#define TEST(x,r,y) ( \
+ (test_mode == PCRE8_MODE && G(x,8) r (y)) || \
+ (test_mode == PCRE16_MODE && G(x,16) r (y)) || \
+ (test_mode == PCRE32_MODE && G(x,32) r (y)))
+
+#define TESTFLD(x,f,r,y) ( \
+ (test_mode == PCRE8_MODE && G(x,8)->f r (y)) || \
+ (test_mode == PCRE16_MODE && G(x,16)->f r (y)) || \
+ (test_mode == PCRE32_MODE && G(x,32)->f r (y)))
+
+
+/* ----- Two out of three modes are supported ----- */
+
+#else
+
+/* We can use some macro trickery to make a single set of definitions work in
+the three different cases. */
+
+/* ----- 32-bit and 16-bit but not 8-bit supported ----- */
+
+#if defined(SUPPORT_PCRE2_32) && defined(SUPPORT_PCRE2_16)
+#define BITONE 32
+#define BITTWO 16
+
+/* ----- 32-bit and 8-bit but not 16-bit supported ----- */
+
+#elif defined(SUPPORT_PCRE2_32) && defined(SUPPORT_PCRE2_8)
+#define BITONE 32
+#define BITTWO 8
+
+/* ----- 16-bit and 8-bit but not 32-bit supported ----- */
+
+#else
+#define BITONE 16
+#define BITTWO 8
+#endif
+
+
+/* ----- Common macros for two-mode cases ----- */
+
+#define BYTEONE (BITONE/8)
+#define BYTETWO (BITTWO/8)
+
+#define CASTFLD(t,a,b) \
+ ((test_mode == G(G(PCRE,BITONE),_MODE))? (t)(G(a,BITONE)->b) : \
+ (t)(G(a,BITTWO)->b))
+
+#define CASTVAR(t,x) ( \
+ (test_mode == G(G(PCRE,BITONE),_MODE))? \
+ (t)G(x,BITONE) : (t)G(x,BITTWO))
+
+#define CODE_UNIT(a,b) ( \
+ (test_mode == G(G(PCRE,BITONE),_MODE))? \
+ (uint32_t)(((G(PCRE2_SPTR,BITONE))(a))[b]) : \
+ (uint32_t)(((G(PCRE2_SPTR,BITTWO))(a))[b]))
+
+#define CONCTXCPY(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_convert_context_,BITONE))); \
+ else \
+ memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_convert_context_,BITTWO)))
+
+#define CONVERT_COPY(a,b,c) \
+ (test_mode == G(G(PCRE,BITONE),_MODE))? \
+ memcpy(G(a,BITONE),(char *)b,(c)*BYTEONE) : \
+ memcpy(G(a,BITTWO),(char *)b,(c)*BYTETWO)
+
+#define DATCTXCPY(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_match_context_,BITONE))); \
+ else \
+ memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_match_context_,BITTWO)))
+
+#define FLD(a,b) \
+ ((test_mode == G(G(PCRE,BITONE),_MODE))? G(a,BITONE)->b : G(a,BITTWO)->b)
+
+#define PATCTXCPY(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ memcpy(G(a,BITONE),G(b,BITONE),sizeof(G(pcre2_compile_context_,BITONE))); \
+ else \
+ memcpy(G(a,BITTWO),G(b,BITTWO),sizeof(G(pcre2_compile_context_,BITTWO)))
+
+#define PCHARS(lv, p, offset, len, utf, f) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ lv = G(pchars,BITONE)((G(PCRE2_SPTR,BITONE))(p)+offset, len, utf, f); \
+ else \
+ lv = G(pchars,BITTWO)((G(PCRE2_SPTR,BITTWO))(p)+offset, len, utf, f)
+
+#define PCHARSV(p, offset, len, utf, f) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ (void)G(pchars,BITONE)((G(PCRE2_SPTR,BITONE))(p)+offset, len, utf, f); \
+ else \
+ (void)G(pchars,BITTWO)((G(PCRE2_SPTR,BITTWO))(p)+offset, len, utf, f)
+
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_callout_enumerate,BITONE)(G(compiled_code,BITONE), \
+ (int (*)(struct G(pcre2_callout_enumerate_block_,BITONE) *, void *))b,c); \
+ else \
+ a = G(pcre2_callout_enumerate,BITTWO)(G(compiled_code,BITTWO), \
+ (int (*)(struct G(pcre2_callout_enumerate_block_,BITTWO) *, void *))b,c)
+
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(a,BITONE) = G(pcre2_code_copy_,BITONE)(b); \
+ else \
+ G(a,BITTWO) = G(pcre2_code_copy_,BITTWO)(b)
+
+#define PCRE2_CODE_COPY_TO_VOID(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = (void *)G(pcre2_code_copy_,BITONE)(G(b,BITONE)); \
+ else \
+ a = (void *)G(pcre2_code_copy_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = (void *)G(pcre2_code_copy_with_tables_,BITONE)(G(b,BITONE)); \
+ else \
+ a = (void *)G(pcre2_code_copy_with_tables_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(a,BITONE) = G(pcre2_compile_,BITONE)(G(b,BITONE),c,d,e,f,g); \
+ else \
+ G(a,BITTWO) = G(pcre2_compile_,BITTWO)(G(b,BITTWO),c,d,e,f,g)
+
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_converted_pattern_free_,BITONE)((G(PCRE2_UCHAR,BITONE) *)a); \
+ else \
+ G(pcre2_converted_pattern_free_,BITTWO)((G(PCRE2_UCHAR,BITTWO) *)a)
+
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_dfa_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+ G(g,BITONE),h,i,j); \
+ else \
+ a = G(pcre2_dfa_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+ G(g,BITTWO),h,i,j)
+
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_get_error_message_,BITONE)(a,G(b,BITONE),G(G(b,BITONE),_size/BYTEONE)); \
+ else \
+ r = G(pcre2_get_error_message_,BITTWO)(a,G(b,BITTWO),G(G(b,BITTWO),_size/BYTETWO))
+
+#define PCRE2_GET_OVECTOR_COUNT(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_get_ovector_count_,BITONE)(G(b,BITONE)); \
+ else \
+ a = G(pcre2_get_ovector_count_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_GET_STARTCHAR(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_get_startchar_,BITONE)(G(b,BITONE)); \
+ else \
+ a = G(pcre2_get_startchar_,BITTWO)(G(b,BITTWO))
+
+#define PCRE2_JIT_COMPILE(r,a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_jit_compile_,BITONE)(G(a,BITONE),b); \
+ else \
+ r = G(pcre2_jit_compile_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_jit_free_unused_memory_,BITONE)(G(a,BITONE)); \
+ else \
+ G(pcre2_jit_free_unused_memory_,BITTWO)(G(a,BITTWO))
+
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_jit_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+ G(g,BITONE),h); \
+ else \
+ a = G(pcre2_jit_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+ G(g,BITTWO),h)
+
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_create_,BITONE)(b,c,d); \
+ else \
+ a = (PCRE2_JIT_STACK *)G(pcre2_jit_stack_create_,BITTWO)(b,c,d); \
+
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_jit_stack_assign_,BITONE)(G(a,BITONE),(G(pcre2_jit_callback_,BITONE))b,c); \
+ else \
+ G(pcre2_jit_stack_assign_,BITTWO)(G(a,BITTWO),(G(pcre2_jit_callback_,BITTWO))b,c);
+
+#define PCRE2_JIT_STACK_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_jit_stack_free_,BITONE)((G(pcre2_jit_stack_,BITONE) *)a); \
+ else \
+ G(pcre2_jit_stack_free_,BITTWO)((G(pcre2_jit_stack_,BITTWO) *)a);
+
+#define PCRE2_MAKETABLES(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_maketables_,BITONE)(NULL); \
+ else \
+ a = G(pcre2_maketables_,BITTWO)(NULL)
+
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_match_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+ G(g,BITONE),h); \
+ else \
+ a = G(pcre2_match_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+ G(g,BITTWO),h)
+
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(a,BITONE) = G(pcre2_match_data_create_,BITONE)(b,c); \
+ else \
+ G(a,BITTWO) = G(pcre2_match_data_create_,BITTWO)(b,c)
+
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(a,BITONE) = G(pcre2_match_data_create_from_pattern_,BITONE)(G(b,BITONE),c); \
+ else \
+ G(a,BITTWO) = G(pcre2_match_data_create_from_pattern_,BITTWO)(G(b,BITTWO),c)
+
+#define PCRE2_MATCH_DATA_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_match_data_free_,BITONE)(G(a,BITONE)); \
+ else \
+ G(pcre2_match_data_free_,BITTWO)(G(a,BITTWO))
+
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_pattern_convert_,BITONE)(G(b,BITONE),c,d,(G(PCRE2_UCHAR,BITONE) **)e,f,G(g,BITONE)); \
+ else \
+ a = G(pcre2_pattern_convert_,BITTWO)(G(b,BITTWO),c,d,(G(PCRE2_UCHAR,BITTWO) **)e,f,G(g,BITTWO))
+
+#define PCRE2_PATTERN_INFO(a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_pattern_info_,BITONE)(G(b,BITONE),c,d); \
+ else \
+ a = G(pcre2_pattern_info_,BITTWO)(G(b,BITTWO),c,d)
+
+#define PCRE2_PRINTINT(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_printint_,BITONE)(G(compiled_code,BITONE),outfile,a); \
+ else \
+ G(pcre2_printint_,BITTWO)(G(compiled_code,BITTWO),outfile,a)
+
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_serialize_decode_,BITONE)((G(pcre2_code_,BITONE) **)a,b,c,G(d,BITONE)); \
+ else \
+ r = G(pcre2_serialize_decode_,BITTWO)((G(pcre2_code_,BITTWO) **)a,b,c,G(d,BITTWO))
+
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_serialize_encode_,BITONE)((G(const pcre2_code_,BITONE) **)a,b,c,d,G(e,BITONE)); \
+ else \
+ r = G(pcre2_serialize_encode_,BITTWO)((G(const pcre2_code_,BITTWO) **)a,b,c,d,G(e,BITTWO))
+
+#define PCRE2_SERIALIZE_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_serialize_free_,BITONE)(a); \
+ else \
+ G(pcre2_serialize_free_,BITTWO)(a)
+
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_serialize_get_number_of_codes_,BITONE)(a); \
+ else \
+ r = G(pcre2_serialize_get_number_of_codes_,BITTWO)(a)
+
+#define PCRE2_SET_CALLOUT(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_callout_,BITONE)(G(a,BITONE), \
+ (int (*)(G(pcre2_callout_block_,BITONE) *, void *))b,c); \
+ else \
+ G(pcre2_set_callout_,BITTWO)(G(a,BITTWO), \
+ (int (*)(G(pcre2_callout_block_,BITTWO) *, void *))b,c);
+
+#define PCRE2_SET_CHARACTER_TABLES(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_character_tables_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_character_tables_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_compile_recursion_guard_,BITONE)(G(a,BITONE),b,c); \
+ else \
+ G(pcre2_set_compile_recursion_guard_,BITTWO)(G(a,BITTWO),b,c)
+
+#define PCRE2_SET_DEPTH_LIMIT(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_depth_limit_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_depth_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_set_glob_escape_,BITONE)(G(a,BITONE),b); \
+ else \
+ r = G(pcre2_set_glob_escape_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ r = G(pcre2_set_glob_separator_,BITONE)(G(a,BITONE),b); \
+ else \
+ r = G(pcre2_set_glob_separator_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_HEAP_LIMIT(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_heap_limit_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_heap_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_MATCH_LIMIT(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_match_limit_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_match_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_max_pattern_length_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_max_pattern_length_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_OFFSET_LIMIT(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_offset_limit_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_offset_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_set_parens_nest_limit_,BITONE)(G(a,BITONE),b); \
+ else \
+ G(pcre2_set_parens_nest_limit_,BITTWO)(G(a,BITTWO),b)
+
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substitute_,BITONE)(G(b,BITONE),(G(PCRE2_SPTR,BITONE))c,d,e,f, \
+ G(g,BITONE),G(h,BITONE),(G(PCRE2_SPTR,BITONE))i,j, \
+ (G(PCRE2_UCHAR,BITONE) *)k,l); \
+ else \
+ a = G(pcre2_substitute_,BITTWO)(G(b,BITTWO),(G(PCRE2_SPTR,BITTWO))c,d,e,f, \
+ G(g,BITTWO),G(h,BITTWO),(G(PCRE2_SPTR,BITTWO))i,j, \
+ (G(PCRE2_UCHAR,BITTWO) *)k,l)
+
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_copy_byname_,BITONE)(G(b,BITONE),G(c,BITONE),\
+ (G(PCRE2_UCHAR,BITONE) *)d,e); \
+ else \
+ a = G(pcre2_substring_copy_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),\
+ (G(PCRE2_UCHAR,BITTWO) *)d,e)
+
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_copy_bynumber_,BITONE)(G(b,BITONE),c,\
+ (G(PCRE2_UCHAR,BITONE) *)d,e); \
+ else \
+ a = G(pcre2_substring_copy_bynumber_,BITTWO)(G(b,BITTWO),c,\
+ (G(PCRE2_UCHAR,BITTWO) *)d,e)
+
+#define PCRE2_SUBSTRING_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_substring_free_,BITONE)((G(PCRE2_UCHAR,BITONE) *)a); \
+ else G(pcre2_substring_free_,BITTWO)((G(PCRE2_UCHAR,BITTWO) *)a)
+
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_get_byname_,BITONE)(G(b,BITONE),G(c,BITONE),\
+ (G(PCRE2_UCHAR,BITONE) **)d,e); \
+ else \
+ a = G(pcre2_substring_get_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),\
+ (G(PCRE2_UCHAR,BITTWO) **)d,e)
+
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_get_bynumber_,BITONE)(G(b,BITONE),c,\
+ (G(PCRE2_UCHAR,BITONE) **)d,e); \
+ else \
+ a = G(pcre2_substring_get_bynumber_,BITTWO)(G(b,BITTWO),c,\
+ (G(PCRE2_UCHAR,BITTWO) **)d,e)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_length_byname_,BITONE)(G(b,BITONE),G(c,BITONE),d); \
+ else \
+ a = G(pcre2_substring_length_byname_,BITTWO)(G(b,BITTWO),G(c,BITTWO),d)
+
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_length_bynumber_,BITONE)(G(b,BITONE),c,d); \
+ else \
+ a = G(pcre2_substring_length_bynumber_,BITTWO)(G(b,BITTWO),c,d)
+
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_list_get_,BITONE)(G(b,BITONE), \
+ (G(PCRE2_UCHAR,BITONE) ***)c,d); \
+ else \
+ a = G(pcre2_substring_list_get_,BITTWO)(G(b,BITTWO), \
+ (G(PCRE2_UCHAR,BITTWO) ***)c,d)
+
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(pcre2_substring_list_free_,BITONE)((G(PCRE2_SPTR,BITONE) *)a); \
+ else \
+ G(pcre2_substring_list_free_,BITTWO)((G(PCRE2_SPTR,BITTWO) *)a)
+
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ a = G(pcre2_substring_number_from_name_,BITONE)(G(b,BITONE),G(c,BITONE)); \
+ else \
+ a = G(pcre2_substring_number_from_name_,BITTWO)(G(b,BITTWO),G(c,BITTWO))
+
+#define PTR(x) ( \
+ (test_mode == G(G(PCRE,BITONE),_MODE))? (void *)G(x,BITONE) : \
+ (void *)G(x,BITTWO))
+
+#define SETFLD(x,y,z) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE)->y = z; \
+ else G(x,BITTWO)->y = z
+
+#define SETFLDVEC(x,y,v,z) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE)->y[v] = z; \
+ else G(x,BITTWO)->y[v] = z
+
+#define SETOP(x,y,z) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) G(x,BITONE) z y; \
+ else G(x,BITTWO) z y
+
+#define SETCASTPTR(x,y) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(x,BITONE) = (G(G(uint,BITONE),_t) *)(y); \
+ else \
+ G(x,BITTWO) = (G(G(uint,BITTWO),_t) *)(y)
+
+#define STRLEN(p) ((test_mode == G(G(PCRE,BITONE),_MODE))? \
+ G(strlen,BITONE)((G(PCRE2_SPTR,BITONE))p) : \
+ G(strlen,BITTWO)((G(PCRE2_SPTR,BITTWO))p))
+
+#define SUB1(a,b) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(a,BITONE)(G(b,BITONE)); \
+ else \
+ G(a,BITTWO)(G(b,BITTWO))
+
+#define SUB2(a,b,c) \
+ if (test_mode == G(G(PCRE,BITONE),_MODE)) \
+ G(a,BITONE))(G(b,BITONE),G(c,BITONE)); \
+ else \
+ G(a,BITTWO))(G(b,BITTWO),G(c,BITTWO))
+
+#define TEST(x,r,y) ( \
+ (test_mode == G(G(PCRE,BITONE),_MODE) && G(x,BITONE) r (y)) || \
+ (test_mode == G(G(PCRE,BITTWO),_MODE) && G(x,BITTWO) r (y)))
+
+#define TESTFLD(x,f,r,y) ( \
+ (test_mode == G(G(PCRE,BITONE),_MODE) && G(x,BITONE)->f r (y)) || \
+ (test_mode == G(G(PCRE,BITTWO),_MODE) && G(x,BITTWO)->f r (y)))
+
+
+#endif /* Two out of three modes */
+
+/* ----- End of cases where more than one mode is supported ----- */
+
+
+/* ----- Only 8-bit mode is supported ----- */
+
+#elif defined SUPPORT_PCRE2_8
+#define CASTFLD(t,a,b) (t)(G(a,8)->b)
+#define CASTVAR(t,x) (t)G(x,8)
+#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR8)(a))[b])
+#define CONCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_convert_context_8))
+#define CONVERT_COPY(a,b,c) memcpy(G(a,8),(char *)b, c)
+#define DATCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_match_context_8))
+#define FLD(a,b) G(a,8)->b
+#define PATCTXCPY(a,b) memcpy(G(a,8),G(b,8),sizeof(pcre2_compile_context_8))
+#define PCHARS(lv, p, offset, len, utf, f) \
+ lv = pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+#define PCHARSV(p, offset, len, utf, f) \
+ (void)pchars8((PCRE2_SPTR8)(p)+offset, len, utf, f)
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+ a = pcre2_callout_enumerate_8(compiled_code8, \
+ (int (*)(struct pcre2_callout_enumerate_block_8 *, void *))b,c)
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,8) = pcre2_code_copy_8(b)
+#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_8(G(b,8))
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_8(G(b,8))
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+ G(a,8) = pcre2_compile_8(G(b,8),c,d,e,f,g)
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+ pcre2_converted_pattern_free_8((PCRE2_UCHAR8 *)a)
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+ a = pcre2_dfa_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h,i,j)
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+ r = pcre2_get_error_message_8(a,G(b,8),G(G(b,8),_size))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_8(G(b,8))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_8(G(b,8))
+#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_8(G(a,8),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_8(G(a,8))
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+ a = pcre2_jit_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h)
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+ a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_8(b,c,d);
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+ pcre2_jit_stack_assign_8(G(a,8),(pcre2_jit_callback_8)b,c);
+#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_8((pcre2_jit_stack_8 *)a);
+#define PCRE2_MAKETABLES(a) a = pcre2_maketables_8(NULL)
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+ a = pcre2_match_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),h)
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,8) = pcre2_match_data_create_8(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+ G(a,8) = pcre2_match_data_create_from_pattern_8(G(b,8),c)
+#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_8(G(a,8))
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_8(G(b,8),c,d,(PCRE2_UCHAR8 **)e,f,G(g,8))
+#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_8(G(b,8),c,d)
+#define PCRE2_PRINTINT(a) pcre2_printint_8(compiled_code8,outfile,a)
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+ r = pcre2_serialize_decode_8((pcre2_code_8 **)a,b,c,G(d,8))
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+ r = pcre2_serialize_encode_8((const pcre2_code_8 **)a,b,c,d,G(e,8))
+#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_8(a)
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+ r = pcre2_serialize_get_number_of_codes_8(a)
+#define PCRE2_SET_CALLOUT(a,b,c) \
+ pcre2_set_callout_8(G(a,8),(int (*)(pcre2_callout_block_8 *, void *))b,c)
+#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_8(G(a,8),b)
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+ pcre2_set_compile_recursion_guard_8(G(a,8),b,c)
+#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_8(G(a,8),b)
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_8(G(a,8),b)
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_8(G(a,8),b)
+#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_8(G(a,8),b)
+#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_8(G(a,8),b)
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_8(G(a,8),b)
+#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_8(G(a,8),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_8(G(a,8),b)
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+ a = pcre2_substitute_8(G(b,8),(PCRE2_SPTR8)c,d,e,f,G(g,8),G(h,8), \
+ (PCRE2_SPTR8)i,j,(PCRE2_UCHAR8 *)k,l)
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+ a = pcre2_substring_copy_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 *)d,e)
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+ a = pcre2_substring_copy_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 *)d,e)
+#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_8((PCRE2_UCHAR8 *)a)
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+ a = pcre2_substring_get_byname_8(G(b,8),G(c,8),(PCRE2_UCHAR8 **)d,e)
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+ a = pcre2_substring_get_bynumber_8(G(b,8),c,(PCRE2_UCHAR8 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+ a = pcre2_substring_length_byname_8(G(b,8),G(c,8),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+ a = pcre2_substring_length_bynumber_8(G(b,8),c,d)
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+ a = pcre2_substring_list_get_8(G(b,8),(PCRE2_UCHAR8 ***)c,d)
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+ pcre2_substring_list_free_8((PCRE2_SPTR8 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+ a = pcre2_substring_number_from_name_8(G(b,8),G(c,8));
+#define PTR(x) (void *)G(x,8)
+#define SETFLD(x,y,z) G(x,8)->y = z
+#define SETFLDVEC(x,y,v,z) G(x,8)->y[v] = z
+#define SETOP(x,y,z) G(x,8) z y
+#define SETCASTPTR(x,y) G(x,8) = (uint8_t *)(y)
+#define STRLEN(p) (int)strlen((char *)p)
+#define SUB1(a,b) G(a,8)(G(b,8))
+#define SUB2(a,b,c) G(a,8)(G(b,8),G(c,8))
+#define TEST(x,r,y) (G(x,8) r (y))
+#define TESTFLD(x,f,r,y) (G(x,8)->f r (y))
+
+
+/* ----- Only 16-bit mode is supported ----- */
+
+#elif defined SUPPORT_PCRE2_16
+#define CASTFLD(t,a,b) (t)(G(a,16)->b)
+#define CASTVAR(t,x) (t)G(x,16)
+#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR16)(a))[b])
+#define CONCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_convert_context_16))
+#define CONVERT_COPY(a,b,c) memcpy(G(a,16),(char *)b, (c)*2)
+#define DATCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_match_context_16))
+#define FLD(a,b) G(a,16)->b
+#define PATCTXCPY(a,b) memcpy(G(a,16),G(b,16),sizeof(pcre2_compile_context_16))
+#define PCHARS(lv, p, offset, len, utf, f) \
+ lv = pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f)
+#define PCHARSV(p, offset, len, utf, f) \
+ (void)pchars16((PCRE2_SPTR16)(p)+offset, len, utf, f)
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+ a = pcre2_callout_enumerate_16(compiled_code16, \
+ (int (*)(struct pcre2_callout_enumerate_block_16 *, void *))b,c)
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,16) = pcre2_code_copy_16(b)
+#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_16(G(b,16))
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_16(G(b,16))
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+ G(a,16) = pcre2_compile_16(G(b,16),c,d,e,f,g)
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+ pcre2_converted_pattern_free_16((PCRE2_UCHAR16 *)a)
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+ a = pcre2_dfa_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h,i,j)
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+ r = pcre2_get_error_message_16(a,G(b,16),G(G(b,16),_size/2))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_16(G(b,16))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_16(G(b,16))
+#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_16(G(a,16),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_16(G(a,16))
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+ a = pcre2_jit_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h)
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+ a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_16(b,c,d);
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+ pcre2_jit_stack_assign_16(G(a,16),(pcre2_jit_callback_16)b,c);
+#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_16((pcre2_jit_stack_16 *)a);
+#define PCRE2_MAKETABLES(a) a = pcre2_maketables_16(NULL)
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+ a = pcre2_match_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),h)
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,16) = pcre2_match_data_create_16(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+ G(a,16) = pcre2_match_data_create_from_pattern_16(G(b,16),c)
+#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_16(G(a,16))
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_16(G(b,16),c,d,(PCRE2_UCHAR16 **)e,f,G(g,16))
+#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_16(G(b,16),c,d)
+#define PCRE2_PRINTINT(a) pcre2_printint_16(compiled_code16,outfile,a)
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+ r = pcre2_serialize_decode_16((pcre2_code_16 **)a,b,c,G(d,16))
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+ r = pcre2_serialize_encode_16((const pcre2_code_16 **)a,b,c,d,G(e,16))
+#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_16(a)
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+ r = pcre2_serialize_get_number_of_codes_16(a)
+#define PCRE2_SET_CALLOUT(a,b,c) \
+ pcre2_set_callout_16(G(a,16),(int (*)(pcre2_callout_block_16 *, void *))b,c);
+#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_16(G(a,16),b)
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+ pcre2_set_compile_recursion_guard_16(G(a,16),b,c)
+#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_16(G(a,16),b)
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_16(G(a,16),b)
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_16(G(a,16),b)
+#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_16(G(a,16),b)
+#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_16(G(a,16),b)
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_16(G(a,16),b)
+#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_16(G(a,16),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_16(G(a,16),b)
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+ a = pcre2_substitute_16(G(b,16),(PCRE2_SPTR16)c,d,e,f,G(g,16),G(h,16), \
+ (PCRE2_SPTR16)i,j,(PCRE2_UCHAR16 *)k,l)
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+ a = pcre2_substring_copy_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 *)d,e)
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+ a = pcre2_substring_copy_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 *)d,e)
+#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_16((PCRE2_UCHAR16 *)a)
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+ a = pcre2_substring_get_byname_16(G(b,16),G(c,16),(PCRE2_UCHAR16 **)d,e)
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+ a = pcre2_substring_get_bynumber_16(G(b,16),c,(PCRE2_UCHAR16 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+ a = pcre2_substring_length_byname_16(G(b,16),G(c,16),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+ a = pcre2_substring_length_bynumber_16(G(b,16),c,d)
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+ a = pcre2_substring_list_get_16(G(b,16),(PCRE2_UCHAR16 ***)c,d)
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+ pcre2_substring_list_free_16((PCRE2_SPTR16 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+ a = pcre2_substring_number_from_name_16(G(b,16),G(c,16));
+#define PTR(x) (void *)G(x,16)
+#define SETFLD(x,y,z) G(x,16)->y = z
+#define SETFLDVEC(x,y,v,z) G(x,16)->y[v] = z
+#define SETOP(x,y,z) G(x,16) z y
+#define SETCASTPTR(x,y) G(x,16) = (uint16_t *)(y)
+#define STRLEN(p) (int)strlen16((PCRE2_SPTR16)p)
+#define SUB1(a,b) G(a,16)(G(b,16))
+#define SUB2(a,b,c) G(a,16)(G(b,16),G(c,16))
+#define TEST(x,r,y) (G(x,16) r (y))
+#define TESTFLD(x,f,r,y) (G(x,16)->f r (y))
+
+
+/* ----- Only 32-bit mode is supported ----- */
+
+#elif defined SUPPORT_PCRE2_32
+#define CASTFLD(t,a,b) (t)(G(a,32)->b)
+#define CASTVAR(t,x) (t)G(x,32)
+#define CODE_UNIT(a,b) (uint32_t)(((PCRE2_SPTR32)(a))[b])
+#define CONCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_convert_context_32))
+#define CONVERT_COPY(a,b,c) memcpy(G(a,32),(char *)b, (c)*4)
+#define DATCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_match_context_32))
+#define FLD(a,b) G(a,32)->b
+#define PATCTXCPY(a,b) memcpy(G(a,32),G(b,32),sizeof(pcre2_compile_context_32))
+#define PCHARS(lv, p, offset, len, utf, f) \
+ lv = pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f)
+#define PCHARSV(p, offset, len, utf, f) \
+ (void)pchars32((PCRE2_SPTR32)(p)+offset, len, utf, f)
+#define PCRE2_CALLOUT_ENUMERATE(a,b,c) \
+ a = pcre2_callout_enumerate_32(compiled_code32, \
+ (int (*)(struct pcre2_callout_enumerate_block_32 *, void *))b,c)
+#define PCRE2_CODE_COPY_FROM_VOID(a,b) G(a,32) = pcre2_code_copy_32(b)
+#define PCRE2_CODE_COPY_TO_VOID(a,b) a = (void *)pcre2_code_copy_32(G(b,32))
+#define PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(a,b) a = (void *)pcre2_code_copy_with_tables_32(G(b,32))
+#define PCRE2_COMPILE(a,b,c,d,e,f,g) \
+ G(a,32) = pcre2_compile_32(G(b,32),c,d,e,f,g)
+#define PCRE2_CONVERTED_PATTERN_FREE(a) \
+ pcre2_converted_pattern_free_32((PCRE2_UCHAR32 *)a)
+#define PCRE2_DFA_MATCH(a,b,c,d,e,f,g,h,i,j) \
+ a = pcre2_dfa_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h,i,j)
+#define PCRE2_GET_ERROR_MESSAGE(r,a,b) \
+ r = pcre2_get_error_message_32(a,G(b,32),G(G(b,32),_size/4))
+#define PCRE2_GET_OVECTOR_COUNT(a,b) a = pcre2_get_ovector_count_32(G(b,32))
+#define PCRE2_GET_STARTCHAR(a,b) a = pcre2_get_startchar_32(G(b,32))
+#define PCRE2_JIT_COMPILE(r,a,b) r = pcre2_jit_compile_32(G(a,32),b)
+#define PCRE2_JIT_FREE_UNUSED_MEMORY(a) pcre2_jit_free_unused_memory_32(G(a,32))
+#define PCRE2_JIT_MATCH(a,b,c,d,e,f,g,h) \
+ a = pcre2_jit_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+#define PCRE2_JIT_STACK_CREATE(a,b,c,d) \
+ a = (PCRE2_JIT_STACK *)pcre2_jit_stack_create_32(b,c,d);
+#define PCRE2_JIT_STACK_ASSIGN(a,b,c) \
+ pcre2_jit_stack_assign_32(G(a,32),(pcre2_jit_callback_32)b,c);
+#define PCRE2_JIT_STACK_FREE(a) pcre2_jit_stack_free_32((pcre2_jit_stack_32 *)a);
+#define PCRE2_MAKETABLES(a) a = pcre2_maketables_32(NULL)
+#define PCRE2_MATCH(a,b,c,d,e,f,g,h) \
+ a = pcre2_match_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),h)
+#define PCRE2_MATCH_DATA_CREATE(a,b,c) G(a,32) = pcre2_match_data_create_32(b,c)
+#define PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(a,b,c) \
+ G(a,32) = pcre2_match_data_create_from_pattern_32(G(b,32),c)
+#define PCRE2_MATCH_DATA_FREE(a) pcre2_match_data_free_32(G(a,32))
+#define PCRE2_PATTERN_CONVERT(a,b,c,d,e,f,g) a = pcre2_pattern_convert_32(G(b,32),c,d,(PCRE2_UCHAR32 **)e,f,G(g,32))
+#define PCRE2_PATTERN_INFO(a,b,c,d) a = pcre2_pattern_info_32(G(b,32),c,d)
+#define PCRE2_PRINTINT(a) pcre2_printint_32(compiled_code32,outfile,a)
+#define PCRE2_SERIALIZE_DECODE(r,a,b,c,d) \
+ r = pcre2_serialize_decode_32((pcre2_code_32 **)a,b,c,G(d,32))
+#define PCRE2_SERIALIZE_ENCODE(r,a,b,c,d,e) \
+ r = pcre2_serialize_encode_32((const pcre2_code_32 **)a,b,c,d,G(e,32))
+#define PCRE2_SERIALIZE_FREE(a) pcre2_serialize_free_32(a)
+#define PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(r,a) \
+ r = pcre2_serialize_get_number_of_codes_32(a)
+#define PCRE2_SET_CALLOUT(a,b,c) \
+ pcre2_set_callout_32(G(a,32),(int (*)(pcre2_callout_block_32 *, void *))b,c);
+#define PCRE2_SET_CHARACTER_TABLES(a,b) pcre2_set_character_tables_32(G(a,32),b)
+#define PCRE2_SET_COMPILE_RECURSION_GUARD(a,b,c) \
+ pcre2_set_compile_recursion_guard_32(G(a,32),b,c)
+#define PCRE2_SET_DEPTH_LIMIT(a,b) pcre2_set_depth_limit_32(G(a,32),b)
+#define PCRE2_SET_GLOB_ESCAPE(r,a,b) r = pcre2_set_glob_escape_32(G(a,32),b)
+#define PCRE2_SET_GLOB_SEPARATOR(r,a,b) r = pcre2_set_glob_separator_32(G(a,32),b)
+#define PCRE2_SET_HEAP_LIMIT(a,b) pcre2_set_heap_limit_32(G(a,32),b)
+#define PCRE2_SET_MATCH_LIMIT(a,b) pcre2_set_match_limit_32(G(a,32),b)
+#define PCRE2_SET_MAX_PATTERN_LENGTH(a,b) pcre2_set_max_pattern_length_32(G(a,32),b)
+#define PCRE2_SET_OFFSET_LIMIT(a,b) pcre2_set_offset_limit_32(G(a,32),b)
+#define PCRE2_SET_PARENS_NEST_LIMIT(a,b) pcre2_set_parens_nest_limit_32(G(a,32),b)
+#define PCRE2_SUBSTITUTE(a,b,c,d,e,f,g,h,i,j,k,l) \
+ a = pcre2_substitute_32(G(b,32),(PCRE2_SPTR32)c,d,e,f,G(g,32),G(h,32), \
+ (PCRE2_SPTR32)i,j,(PCRE2_UCHAR32 *)k,l)
+#define PCRE2_SUBSTRING_COPY_BYNAME(a,b,c,d,e) \
+ a = pcre2_substring_copy_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 *)d,e)
+#define PCRE2_SUBSTRING_COPY_BYNUMBER(a,b,c,d,e) \
+ a = pcre2_substring_copy_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 *)d,e);
+#define PCRE2_SUBSTRING_FREE(a) pcre2_substring_free_32((PCRE2_UCHAR32 *)a)
+#define PCRE2_SUBSTRING_GET_BYNAME(a,b,c,d,e) \
+ a = pcre2_substring_get_byname_32(G(b,32),G(c,32),(PCRE2_UCHAR32 **)d,e)
+#define PCRE2_SUBSTRING_GET_BYNUMBER(a,b,c,d,e) \
+ a = pcre2_substring_get_bynumber_32(G(b,32),c,(PCRE2_UCHAR32 **)d,e)
+#define PCRE2_SUBSTRING_LENGTH_BYNAME(a,b,c,d) \
+ a = pcre2_substring_length_byname_32(G(b,32),G(c,32),d)
+#define PCRE2_SUBSTRING_LENGTH_BYNUMBER(a,b,c,d) \
+ a = pcre2_substring_length_bynumber_32(G(b,32),c,d)
+#define PCRE2_SUBSTRING_LIST_GET(a,b,c,d) \
+ a = pcre2_substring_list_get_32(G(b,32),(PCRE2_UCHAR32 ***)c,d)
+#define PCRE2_SUBSTRING_LIST_FREE(a) \
+ pcre2_substring_list_free_32((PCRE2_SPTR32 *)a)
+#define PCRE2_SUBSTRING_NUMBER_FROM_NAME(a,b,c) \
+ a = pcre2_substring_number_from_name_32(G(b,32),G(c,32));
+#define PTR(x) (void *)G(x,32)
+#define SETFLD(x,y,z) G(x,32)->y = z
+#define SETFLDVEC(x,y,v,z) G(x,32)->y[v] = z
+#define SETOP(x,y,z) G(x,32) z y
+#define SETCASTPTR(x,y) G(x,32) = (uint32_t *)(y)
+#define STRLEN(p) (int)strlen32((PCRE2_SPTR32)p)
+#define SUB1(a,b) G(a,32)(G(b,32))
+#define SUB2(a,b,c) G(a,32)(G(b,32),G(c,32))
+#define TEST(x,r,y) (G(x,32) r (y))
+#define TESTFLD(x,f,r,y) (G(x,32)->f r (y))
+
+#endif
+
+/* ----- End of mode-specific function call macros ----- */
+
+
+
+
+/*************************************************
+* Alternate character tables *
+*************************************************/
+
+/* By default, the "tables" pointer in the compile context when calling
+pcre2_compile() is not set (= NULL), thereby using the default tables of the
+library. However, the tables modifier can be used to select alternate sets of
+tables, for different kinds of testing. Note that the locale modifier also
+adjusts the tables. */
+
+/* This is the set of tables distributed as default with PCRE2. It recognizes
+only ASCII characters. */
+
+static const uint8_t tables1[] = {
+
+/* This table is a lower casing table. */
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,
+ 168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,
+ 184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,
+ 200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,
+ 232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255,
+
+/* This table is a case flipping table. */
+
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 97, 98, 99,100,101,102,103,
+ 104,105,106,107,108,109,110,111,
+ 112,113,114,115,116,117,118,119,
+ 120,121,122, 91, 92, 93, 94, 95,
+ 96, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90,123,124,125,126,127,
+ 128,129,130,131,132,133,134,135,
+ 136,137,138,139,140,141,142,143,
+ 144,145,146,147,148,149,150,151,
+ 152,153,154,155,156,157,158,159,
+ 160,161,162,163,164,165,166,167,
+ 168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,
+ 184,185,186,187,188,189,190,191,
+ 192,193,194,195,196,197,198,199,
+ 200,201,202,203,204,205,206,207,
+ 208,209,210,211,212,213,214,215,
+ 216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,
+ 232,233,234,235,236,237,238,239,
+ 240,241,242,243,244,245,246,247,
+ 248,249,250,251,252,253,254,255,
+
+/* This table contains bit maps for various character classes. Each map is 32
+bytes long and the bits run from the least significant end of each byte. The
+classes that have their own maps are: space, xdigit, digit, upper, lower, word,
+graph, print, punct, and cntrl. Other classes are built from combinations. */
+
+ 0x00,0x3e,0x00,0x00,0x01,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0x7e,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xfe,0xff,0xff,0x07,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
+ 0xfe,0xff,0xff,0x87,0xfe,0xff,0xff,0x07,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00,0xfe,0xff,0x00,0xfc,
+ 0x01,0x00,0x00,0xf8,0x01,0x00,0x00,0x78,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+
+/* This table identifies various classes of character by individual bits:
+ 0x01 white space character
+ 0x02 letter
+ 0x04 decimal digit
+ 0x08 hexadecimal digit
+ 0x10 alphanumeric or '_'
+ 0x80 regular expression metacharacter or binary zero
+*/
+
+ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 0- 7 */
+ 0x00,0x01,0x01,0x01,0x01,0x01,0x00,0x00, /* 8- 15 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 16- 23 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 24- 31 */
+ 0x01,0x00,0x00,0x00,0x80,0x00,0x00,0x00, /* - ' */
+ 0x80,0x80,0x80,0x80,0x00,0x00,0x80,0x00, /* ( - / */
+ 0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c,0x1c, /* 0 - 7 */
+ 0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,0x80, /* 8 - ? */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* @ - G */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* H - O */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* P - W */
+ 0x12,0x12,0x12,0x80,0x80,0x00,0x80,0x10, /* X - _ */
+ 0x00,0x1a,0x1a,0x1a,0x1a,0x1a,0x1a,0x12, /* ` - g */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* h - o */
+ 0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12, /* p - w */
+ 0x12,0x12,0x12,0x80,0x80,0x00,0x00,0x00, /* x -127 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 128-135 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 136-143 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 144-151 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 152-159 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 160-167 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 168-175 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 176-183 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 184-191 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 192-199 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 200-207 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 208-215 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 216-223 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 224-231 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 232-239 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 240-247 */
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};/* 248-255 */
+
+/* This is a set of tables that came originally from a Windows user. It seems
+to be at least an approximation of ISO 8859. In particular, there are
+characters greater than 128 that are marked as spaces, letters, etc. */
+
+static const uint8_t tables2[] = {
+0,1,2,3,4,5,6,7,
+8,9,10,11,12,13,14,15,
+16,17,18,19,20,21,22,23,
+24,25,26,27,28,29,30,31,
+32,33,34,35,36,37,38,39,
+40,41,42,43,44,45,46,47,
+48,49,50,51,52,53,54,55,
+56,57,58,59,60,61,62,63,
+64,97,98,99,100,101,102,103,
+104,105,106,107,108,109,110,111,
+112,113,114,115,116,117,118,119,
+120,121,122,91,92,93,94,95,
+96,97,98,99,100,101,102,103,
+104,105,106,107,108,109,110,111,
+112,113,114,115,116,117,118,119,
+120,121,122,123,124,125,126,127,
+128,129,130,131,132,133,134,135,
+136,137,138,139,140,141,142,143,
+144,145,146,147,148,149,150,151,
+152,153,154,155,156,157,158,159,
+160,161,162,163,164,165,166,167,
+168,169,170,171,172,173,174,175,
+176,177,178,179,180,181,182,183,
+184,185,186,187,188,189,190,191,
+224,225,226,227,228,229,230,231,
+232,233,234,235,236,237,238,239,
+240,241,242,243,244,245,246,215,
+248,249,250,251,252,253,254,223,
+224,225,226,227,228,229,230,231,
+232,233,234,235,236,237,238,239,
+240,241,242,243,244,245,246,247,
+248,249,250,251,252,253,254,255,
+0,1,2,3,4,5,6,7,
+8,9,10,11,12,13,14,15,
+16,17,18,19,20,21,22,23,
+24,25,26,27,28,29,30,31,
+32,33,34,35,36,37,38,39,
+40,41,42,43,44,45,46,47,
+48,49,50,51,52,53,54,55,
+56,57,58,59,60,61,62,63,
+64,97,98,99,100,101,102,103,
+104,105,106,107,108,109,110,111,
+112,113,114,115,116,117,118,119,
+120,121,122,91,92,93,94,95,
+96,65,66,67,68,69,70,71,
+72,73,74,75,76,77,78,79,
+80,81,82,83,84,85,86,87,
+88,89,90,123,124,125,126,127,
+128,129,130,131,132,133,134,135,
+136,137,138,139,140,141,142,143,
+144,145,146,147,148,149,150,151,
+152,153,154,155,156,157,158,159,
+160,161,162,163,164,165,166,167,
+168,169,170,171,172,173,174,175,
+176,177,178,179,180,181,182,183,
+184,185,186,187,188,189,190,191,
+224,225,226,227,228,229,230,231,
+232,233,234,235,236,237,238,239,
+240,241,242,243,244,245,246,215,
+248,249,250,251,252,253,254,223,
+192,193,194,195,196,197,198,199,
+200,201,202,203,204,205,206,207,
+208,209,210,211,212,213,214,247,
+216,217,218,219,220,221,222,255,
+0,62,0,0,1,0,0,0,
+0,0,0,0,0,0,0,0,
+32,0,0,0,1,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,255,3,
+126,0,0,0,126,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,255,3,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,12,2,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+254,255,255,7,0,0,0,0,
+0,0,0,0,0,0,0,0,
+255,255,127,127,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,254,255,255,7,
+0,0,0,0,0,4,32,4,
+0,0,0,128,255,255,127,255,
+0,0,0,0,0,0,255,3,
+254,255,255,135,254,255,255,7,
+0,0,0,0,0,4,44,6,
+255,255,127,255,255,255,127,255,
+0,0,0,0,254,255,255,255,
+255,255,255,255,255,255,255,127,
+0,0,0,0,254,255,255,255,
+255,255,255,255,255,255,255,255,
+0,2,0,0,255,255,255,255,
+255,255,255,255,255,255,255,127,
+0,0,0,0,255,255,255,255,
+255,255,255,255,255,255,255,255,
+0,0,0,0,254,255,0,252,
+1,0,0,248,1,0,0,120,
+0,0,0,0,254,255,255,255,
+0,0,128,0,0,0,128,0,
+255,255,255,255,0,0,0,0,
+0,0,0,0,0,0,0,128,
+255,255,255,255,0,0,0,0,
+0,0,0,0,0,0,0,0,
+128,0,0,0,0,0,0,0,
+0,1,1,0,1,1,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+1,0,0,0,128,0,0,0,
+128,128,128,128,0,0,128,0,
+28,28,28,28,28,28,28,28,
+28,28,0,0,0,0,0,128,
+0,26,26,26,26,26,26,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,128,128,0,128,16,
+0,26,26,26,26,26,26,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,128,128,0,0,0,
+0,0,0,0,0,1,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+1,0,0,0,0,0,0,0,
+0,0,18,0,0,0,0,0,
+0,0,20,20,0,18,0,0,
+0,20,18,0,0,0,0,0,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,0,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,18,
+18,18,18,18,18,18,18,0,
+18,18,18,18,18,18,18,18
+};
+
+
+
+#if !defined(VPCOMPAT) && !defined(HAVE_MEMMOVE)
+/*************************************************
+* Emulated memmove() for systems without it *
+*************************************************/
+
+/* This function can make use of bcopy() if it is available. Otherwise do it by
+steam, as there are some non-Unix environments that lack both memmove() and
+bcopy(). */
+
+static void *
+emulated_memmove(void *d, const void *s, size_t n)
+{
+#ifdef HAVE_BCOPY
+bcopy(s, d, n);
+return d;
+#else
+size_t i;
+unsigned char *dest = (unsigned char *)d;
+const unsigned char *src = (const unsigned char *)s;
+if (dest > src)
+ {
+ dest += n;
+ src += n;
+ for (i = 0; i < n; ++i) *(--dest) = *(--src);
+ return (void *)dest;
+ }
+else
+ {
+ for (i = 0; i < n; ++i) *dest++ = *src++;
+ return (void *)(dest - n);
+ }
+#endif /* not HAVE_BCOPY */
+}
+#undef memmove
+#define memmove(d,s,n) emulated_memmove(d,s,n)
+#endif /* not VPCOMPAT && not HAVE_MEMMOVE */
+
+
+
+#ifndef HAVE_STRERROR
+/*************************************************
+* Provide strerror() for non-ANSI libraries *
+*************************************************/
+
+/* Some old-fashioned systems (e.g. SunOS4) didn't have strerror() in their
+libraries. They may no longer be around, but just in case, we can try to
+provide the same facility by this simple alternative function. */
+
+extern int sys_nerr;
+extern char *sys_errlist[];
+
+char *
+strerror(int n)
+{
+if (n < 0 || n >= sys_nerr) return "unknown error number";
+return sys_errlist[n];
+}
+#endif /* HAVE_STRERROR */
+
+
+
+/*************************************************
+* Local memory functions *
+*************************************************/
+
+/* Alternative memory functions, to test functionality. */
+
+static void *my_malloc(PCRE2_SIZE size, void *data)
+{
+void *block = malloc(size);
+(void)data;
+if (show_memory)
+ {
+ if (block == NULL)
+ {
+ fprintf(outfile, "** malloc() failed for %" SIZ_FORM "\n", SIZ_CAST size);
+ }
+ else
+ {
+ fprintf(outfile, "malloc %5" SIZ_FORM, SIZ_CAST size);
+#ifdef DEBUG_SHOW_MALLOC_ADDRESSES
+ fprintf(outfile, " %p", block); /* Not portable */
+#endif
+ if (malloclistptr < MALLOCLISTSIZE)
+ {
+ malloclist[malloclistptr] = block;
+ malloclistlength[malloclistptr++] = size;
+ }
+ else
+ fprintf(outfile, " (not remembered)");
+ fprintf(outfile, "\n");
+ }
+ }
+return block;
+}
+
+static void my_free(void *block, void *data)
+{
+(void)data;
+if (show_memory)
+ {
+ uint32_t i, j;
+ BOOL found = FALSE;
+
+ fprintf(outfile, "free");
+ for (i = 0; i < malloclistptr; i++)
+ {
+ if (block == malloclist[i])
+ {
+ fprintf(outfile, " %5" SIZ_FORM, SIZ_CAST malloclistlength[i]);
+ malloclistptr--;
+ for (j = i; j < malloclistptr; j++)
+ {
+ malloclist[j] = malloclist[j+1];
+ malloclistlength[j] = malloclistlength[j+1];
+ }
+ found = TRUE;
+ break;
+ }
+ }
+ if (!found) fprintf(outfile, " unremembered block");
+#ifdef DEBUG_SHOW_MALLOC_ADDRESSES
+ fprintf(outfile, " %p", block); /* Not portable */
+#endif
+ fprintf(outfile, "\n");
+ }
+free(block);
+}
+
+
+
+/*************************************************
+* Callback function for stack guard *
+*************************************************/
+
+/* This is set up to be called from pcre2_compile() when the stackguard=n
+modifier sets a value greater than zero. The test we do is whether the
+parenthesis nesting depth is greater than the value set by the modifier.
+
+Argument: the current parenthesis nesting depth
+Returns: non-zero to kill the compilation
+*/
+
+static int
+stack_guard(uint32_t depth, void *user_data)
+{
+(void)user_data;
+return depth > pat_patctl.stackguard_test;
+}
+
+
+/*************************************************
+* JIT memory callback *
+*************************************************/
+
+static PCRE2_JIT_STACK*
+jit_callback(void *arg)
+{
+jit_was_used = TRUE;
+return (PCRE2_JIT_STACK *)arg;
+}
+
+
+/*************************************************
+* Convert UTF-8 character to code point *
+*************************************************/
+
+/* This function reads one or more bytes that represent a UTF-8 character,
+and returns the codepoint of that character. Note that the function supports
+the original UTF-8 definition of RFC 2279, allowing for values in the range 0
+to 0x7fffffff, up to 6 bytes long. This makes it possible to generate
+codepoints greater than 0x10ffff which are useful for testing PCRE2's error
+checking, and also for generating 32-bit non-UTF data values above the UTF
+limit.
+
+Argument:
+ utf8bytes a pointer to the byte vector
+ vptr a pointer to an int to receive the value
+
+Returns: > 0 => the number of bytes consumed
+ -6 to 0 => malformed UTF-8 character at offset = (-return)
+*/
+
+static int
+utf82ord(PCRE2_SPTR8 utf8bytes, uint32_t *vptr)
+{
+uint32_t c = *utf8bytes++;
+uint32_t d = c;
+int i, j, s;
+
+for (i = -1; i < 6; i++) /* i is number of additional bytes */
+ {
+ if ((d & 0x80) == 0) break;
+ d <<= 1;
+ }
+
+if (i == -1) { *vptr = c; return 1; } /* ascii character */
+if (i == 0 || i == 6) return 0; /* invalid UTF-8 */
+
+/* i now has a value in the range 1-5 */
+
+s = 6*i;
+d = (c & utf8_table3[i]) << s;
+
+for (j = 0; j < i; j++)
+ {
+ c = *utf8bytes++;
+ if ((c & 0xc0) != 0x80) return -(j+1);
+ s -= 6;
+ d |= (c & 0x3f) << s;
+ }
+
+/* Check that encoding was the correct unique one */
+
+for (j = 0; j < utf8_table1_size; j++)
+ if (d <= (uint32_t)utf8_table1[j]) break;
+if (j != i) return -(i+1);
+
+/* Valid value */
+
+*vptr = d;
+return i+1;
+}
+
+
+
+/*************************************************
+* Print one character *
+*************************************************/
+
+/* Print a single character either literally, or as a hex escape, and count how
+many printed characters are used.
+
+Arguments:
+ c the character
+ utf TRUE in UTF mode
+ f the FILE to print to, or NULL just to count characters
+
+Returns: number of characters written
+*/
+
+static int
+pchar(uint32_t c, BOOL utf, FILE *f)
+{
+int n = 0;
+char tempbuffer[16];
+
+if (PRINTOK(c))
+ {
+ if (f != NULL) fprintf(f, "%c", c);
+ return 1;
+ }
+
+if (c < 0x100)
+ {
+ if (utf)
+ {
+ if (f != NULL) fprintf(f, "\\x{%02x}", c);
+ return 6;
+ }
+ else
+ {
+ if (f != NULL) fprintf(f, "\\x%02x", c);
+ return 4;
+ }
+ }
+
+if (f != NULL) n = fprintf(f, "\\x{%02x}", c);
+ else n = sprintf(tempbuffer, "\\x{%02x}", c);
+
+return n >= 0 ? n : 0;
+}
+
+
+
+#ifdef SUPPORT_PCRE2_16
+/*************************************************
+* Find length of 0-terminated 16-bit string *
+*************************************************/
+
+static size_t strlen16(PCRE2_SPTR16 p)
+{
+PCRE2_SPTR16 pp = p;
+while (*pp != 0) pp++;
+return (int)(pp - p);
+}
+#endif /* SUPPORT_PCRE2_16 */
+
+
+
+#ifdef SUPPORT_PCRE2_32
+/*************************************************
+* Find length of 0-terminated 32-bit string *
+*************************************************/
+
+static size_t strlen32(PCRE2_SPTR32 p)
+{
+PCRE2_SPTR32 pp = p;
+while (*pp != 0) pp++;
+return (int)(pp - p);
+}
+#endif /* SUPPORT_PCRE2_32 */
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+* Print 8-bit character string *
+*************************************************/
+
+/* Must handle UTF-8 strings in utf8 mode. Yields number of characters printed.
+For printing *MARK strings, a negative length is given. If handed a NULL file,
+just counts chars without printing (because pchar() does that). */
+
+static int pchars8(PCRE2_SPTR8 p, int length, BOOL utf, FILE *f)
+{
+uint32_t c = 0;
+int yield = 0;
+
+if (length < 0) length = p[-1];
+while (length-- > 0)
+ {
+ if (utf)
+ {
+ int rc = utf82ord(p, &c);
+ if (rc > 0 && rc <= length + 1) /* Mustn't run over the end */
+ {
+ length -= rc - 1;
+ p += rc;
+ yield += pchar(c, utf, f);
+ continue;
+ }
+ }
+ c = *p++;
+ yield += pchar(c, utf, f);
+ }
+
+return yield;
+}
+#endif
+
+
+#ifdef SUPPORT_PCRE2_16
+/*************************************************
+* Print 16-bit character string *
+*************************************************/
+
+/* Must handle UTF-16 strings in utf mode. Yields number of characters printed.
+For printing *MARK strings, a negative length is given. If handed a NULL file,
+just counts chars without printing. */
+
+static int pchars16(PCRE2_SPTR16 p, int length, BOOL utf, FILE *f)
+{
+int yield = 0;
+if (length < 0) length = p[-1];
+while (length-- > 0)
+ {
+ uint32_t c = *p++ & 0xffff;
+ if (utf && c >= 0xD800 && c < 0xDC00 && length > 0)
+ {
+ int d = *p & 0xffff;
+ if (d >= 0xDC00 && d <= 0xDFFF)
+ {
+ c = ((c & 0x3ff) << 10) + (d & 0x3ff) + 0x10000;
+ length--;
+ p++;
+ }
+ }
+ yield += pchar(c, utf, f);
+ }
+return yield;
+}
+#endif /* SUPPORT_PCRE2_16 */
+
+
+
+#ifdef SUPPORT_PCRE2_32
+/*************************************************
+* Print 32-bit character string *
+*************************************************/
+
+/* Must handle UTF-32 strings in utf mode. Yields number of characters printed.
+For printing *MARK strings, a negative length is given. If handed a NULL file,
+just counts chars without printing. */
+
+static int pchars32(PCRE2_SPTR32 p, int length, BOOL utf, FILE *f)
+{
+int yield = 0;
+(void)(utf); /* Avoid compiler warning */
+
+if (length < 0) length = p[-1];
+while (length-- > 0)
+ {
+ uint32_t c = *p++;
+ yield += pchar(c, utf, f);
+ }
+return yield;
+}
+#endif /* SUPPORT_PCRE2_32 */
+
+
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+* Convert character value to UTF-8 *
+*************************************************/
+
+/* This function takes an integer value in the range 0 - 0x7fffffff
+and encodes it as a UTF-8 character in 0 to 6 bytes.
+
+Arguments:
+ cvalue the character value
+ utf8bytes pointer to buffer for result - at least 6 bytes long
+
+Returns: number of characters placed in the buffer
+*/
+
+static int
+ord2utf8(uint32_t cvalue, uint8_t *utf8bytes)
+{
+int i, j;
+if (cvalue > 0x7fffffffu)
+ return -1;
+for (i = 0; i < utf8_table1_size; i++)
+ if (cvalue <= (uint32_t)utf8_table1[i]) break;
+utf8bytes += i;
+for (j = i; j > 0; j--)
+ {
+ *utf8bytes-- = 0x80 | (cvalue & 0x3f);
+ cvalue >>= 6;
+ }
+*utf8bytes = utf8_table2[i] | cvalue;
+return i + 1;
+}
+#endif /* SUPPORT_PCRE2_8 */
+
+
+
+#ifdef SUPPORT_PCRE2_16
+/*************************************************
+* Convert string to 16-bit *
+*************************************************/
+
+/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using
+the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and
+code values from 0 to 0x7fffffff. However, values greater than the later UTF
+limit of 0x10ffff cause an error. In non-UTF mode the input is interpreted as
+UTF-8 if the utf8_input modifier is set, but an error is generated for values
+greater than 0xffff.
+
+If all the input bytes are ASCII, the space needed for a 16-bit string is
+exactly double the 8-bit size. Otherwise, the size needed for a 16-bit string
+is no more than double, because up to 0xffff uses no more than 3 bytes in UTF-8
+but possibly 4 in UTF-16. Higher values use 4 bytes in UTF-8 and up to 4 bytes
+in UTF-16. The result is always left in pbuffer16. Impose a minimum size to
+save repeated re-sizing.
+
+Note that this function does not object to surrogate values. This is
+deliberate; it makes it possible to construct UTF-16 strings that are invalid,
+for the purpose of testing that they are correctly faulted.
+
+Arguments:
+ p points to a byte string
+ utf true in UTF mode
+ lenptr points to number of bytes in the string (excluding trailing zero)
+
+Returns: 0 on success, with the length updated to the number of 16-bit
+ data items used (excluding the trailing zero)
+ OR -1 if a UTF-8 string is malformed
+ OR -2 if a value > 0x10ffff is encountered in UTF mode
+ OR -3 if a value > 0xffff is encountered when not in UTF mode
+*/
+
+static PCRE2_SIZE
+to16(uint8_t *p, int utf, PCRE2_SIZE *lenptr)
+{
+uint16_t *pp;
+PCRE2_SIZE len = *lenptr;
+
+if (pbuffer16_size < 2*len + 2)
+ {
+ if (pbuffer16 != NULL) free(pbuffer16);
+ pbuffer16_size = 2*len + 2;
+ if (pbuffer16_size < 4096) pbuffer16_size = 4096;
+ pbuffer16 = (uint16_t *)malloc(pbuffer16_size);
+ if (pbuffer16 == NULL)
+ {
+ fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer16\n",
+ SIZ_CAST pbuffer16_size);
+ exit(1);
+ }
+ }
+
+pp = pbuffer16;
+if (!utf && (pat_patctl.control & CTL_UTF8_INPUT) == 0)
+ {
+ for (; len > 0; len--) *pp++ = *p++;
+ }
+else while (len > 0)
+ {
+ uint32_t c;
+ int chlen = utf82ord(p, &c);
+ if (chlen <= 0) return -1;
+ if (!utf && c > 0xffff) return -3;
+ if (c > 0x10ffff) return -2;
+ p += chlen;
+ len -= chlen;
+ if (c < 0x10000) *pp++ = c; else
+ {
+ c -= 0x10000;
+ *pp++ = 0xD800 | (c >> 10);
+ *pp++ = 0xDC00 | (c & 0x3ff);
+ }
+ }
+
+*pp = 0;
+*lenptr = pp - pbuffer16;
+return 0;
+}
+#endif
+
+
+
+#ifdef SUPPORT_PCRE2_32
+/*************************************************
+* Convert string to 32-bit *
+*************************************************/
+
+/* In UTF mode the input is always interpreted as a string of UTF-8 bytes using
+the original UTF-8 definition of RFC 2279, which allows for up to 6 bytes, and
+code values from 0 to 0x7fffffff. However, values greater than the later UTF
+limit of 0x10ffff cause an error.
+
+In non-UTF mode the input is interpreted as UTF-8 if the utf8_input modifier
+is set, and no limit is imposed. There is special interpretation of the 0xff
+byte (which is illegal in UTF-8) in this case: it causes the top bit of the
+next character to be set. This provides a way of generating 32-bit characters
+greater than 0x7fffffff.
+
+If all the input bytes are ASCII, the space needed for a 32-bit string is
+exactly four times the 8-bit size. Otherwise, the size needed for a 32-bit
+string is no more than four times, because the number of characters must be
+less than the number of bytes. The result is always left in pbuffer32. Impose a
+minimum size to save repeated re-sizing.
+
+Note that this function does not object to surrogate values. This is
+deliberate; it makes it possible to construct UTF-32 strings that are invalid,
+for the purpose of testing that they are correctly faulted.
+
+Arguments:
+ p points to a byte string
+ utf true in UTF mode
+ lenptr points to number of bytes in the string (excluding trailing zero)
+
+Returns: 0 on success, with the length updated to the number of 32-bit
+ data items used (excluding the trailing zero)
+ OR -1 if a UTF-8 string is malformed
+ OR -2 if a value > 0x10ffff is encountered in UTF mode
+*/
+
+static PCRE2_SIZE
+to32(uint8_t *p, int utf, PCRE2_SIZE *lenptr)
+{
+uint32_t *pp;
+PCRE2_SIZE len = *lenptr;
+
+if (pbuffer32_size < 4*len + 4)
+ {
+ if (pbuffer32 != NULL) free(pbuffer32);
+ pbuffer32_size = 4*len + 4;
+ if (pbuffer32_size < 8192) pbuffer32_size = 8192;
+ pbuffer32 = (uint32_t *)malloc(pbuffer32_size);
+ if (pbuffer32 == NULL)
+ {
+ fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer32\n",
+ SIZ_CAST pbuffer32_size);
+ exit(1);
+ }
+ }
+
+pp = pbuffer32;
+
+if (!utf && (pat_patctl.control & CTL_UTF8_INPUT) == 0)
+ {
+ for (; len > 0; len--) *pp++ = *p++;
+ }
+
+else while (len > 0)
+ {
+ int chlen;
+ uint32_t c;
+ uint32_t topbit = 0;
+ if (!utf && *p == 0xff && len > 1)
+ {
+ topbit = 0x80000000u;
+ p++;
+ len--;
+ }
+ chlen = utf82ord(p, &c);
+ if (chlen <= 0) return -1;
+ if (utf && c > 0x10ffff) return -2;
+ p += chlen;
+ len -= chlen;
+ *pp++ = c | topbit;
+ }
+
+*pp = 0;
+*lenptr = pp - pbuffer32;
+return 0;
+}
+#endif /* SUPPORT_PCRE2_32 */
+
+
+
+/*************************************************
+* Move back by so many characters *
+*************************************************/
+
+/* Given a code unit offset in a subject string, move backwards by a number of
+characters, and return the resulting offset.
+
+Arguments:
+ subject pointer to the string
+ offset start offset
+ count count to move back by
+ utf TRUE if in UTF mode
+
+Returns: a possibly changed offset
+*/
+
+static PCRE2_SIZE
+backchars(uint8_t *subject, PCRE2_SIZE offset, uint32_t count, BOOL utf)
+{
+if (!utf || test_mode == PCRE32_MODE)
+ return (count >= offset)? 0 : (offset - count);
+
+else if (test_mode == PCRE8_MODE)
+ {
+ PCRE2_SPTR8 pp = (PCRE2_SPTR8)subject + offset;
+ for (; count > 0 && pp > (PCRE2_SPTR8)subject; count--)
+ {
+ pp--;
+ while ((*pp & 0xc0) == 0x80) pp--;
+ }
+ return pp - (PCRE2_SPTR8)subject;
+ }
+
+else /* 16-bit mode */
+ {
+ PCRE2_SPTR16 pp = (PCRE2_SPTR16)subject + offset;
+ for (; count > 0 && pp > (PCRE2_SPTR16)subject; count--)
+ {
+ pp--;
+ if ((*pp & 0xfc00) == 0xdc00) pp--;
+ }
+ return pp - (PCRE2_SPTR16)subject;
+ }
+}
+
+
+
+/*************************************************
+* Expand input buffers *
+*************************************************/
+
+/* This function doubles the size of the input buffer and the buffer for
+keeping an 8-bit copy of patterns (pbuffer8), and copies the current buffers to
+the new ones.
+
+Arguments: none
+Returns: nothing (aborts if malloc() fails)
+*/
+
+static void
+expand_input_buffers(void)
+{
+int new_pbuffer8_size = 2*pbuffer8_size;
+uint8_t *new_buffer = (uint8_t *)malloc(new_pbuffer8_size);
+uint8_t *new_pbuffer8 = (uint8_t *)malloc(new_pbuffer8_size);
+
+if (new_buffer == NULL || new_pbuffer8 == NULL)
+ {
+ fprintf(stderr, "pcre2test: malloc(%d) failed\n", new_pbuffer8_size);
+ exit(1);
+ }
+
+memcpy(new_buffer, buffer, pbuffer8_size);
+memcpy(new_pbuffer8, pbuffer8, pbuffer8_size);
+
+pbuffer8_size = new_pbuffer8_size;
+
+free(buffer);
+free(pbuffer8);
+
+buffer = new_buffer;
+pbuffer8 = new_pbuffer8;
+}
+
+
+
+/*************************************************
+* Read or extend an input line *
+*************************************************/
+
+/* Input lines are read into buffer, but both patterns and data lines can be
+continued over multiple input lines. In addition, if the buffer fills up, we
+want to automatically expand it so as to be able to handle extremely large
+lines that are needed for certain stress tests, although this is less likely
+now that there are repetition features for both patterns and data. When the
+input buffer is expanded, the other two buffers must also be expanded likewise,
+and the contents of pbuffer, which are a copy of the input for callouts, must
+be preserved (for when expansion happens for a data line). This is not the most
+optimal way of handling this, but hey, this is just a test program!
+
+Arguments:
+ f the file to read
+ start where in buffer to start (this *must* be within buffer)
+ prompt for stdin or readline()
+
+Returns: pointer to the start of new data
+ could be a copy of start, or could be moved
+ NULL if no data read and EOF reached
+*/
+
+static uint8_t *
+extend_inputline(FILE *f, uint8_t *start, const char *prompt)
+{
+uint8_t *here = start;
+
+for (;;)
+ {
+ size_t rlen = (size_t)(pbuffer8_size - (here - buffer));
+
+ if (rlen > 1000)
+ {
+ size_t dlen;
+
+ /* If libreadline or libedit support is required, use readline() to read a
+ line if the input is a terminal. Note that readline() removes the trailing
+ newline, so we must put it back again, to be compatible with fgets(). */
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+ if (INTERACTIVE(f))
+ {
+ size_t len;
+ char *s = readline(prompt);
+ if (s == NULL) return (here == start)? NULL : start;
+ len = strlen(s);
+ if (len > 0) add_history(s);
+ if (len > rlen - 1) len = rlen - 1;
+ memcpy(here, s, len);
+ here[len] = '\n';
+ here[len+1] = 0;
+ free(s);
+ }
+ else
+#endif
+
+ /* Read the next line by normal means, prompting if the file is a tty. */
+
+ {
+ if (INTERACTIVE(f)) printf("%s", prompt);
+ if (fgets((char *)here, rlen, f) == NULL)
+ return (here == start)? NULL : start;
+ }
+
+ dlen = strlen((char *)here);
+ here += dlen;
+
+ /* Check for end of line reached. Take care not to read data from before
+ start (dlen will be zero for a file starting with a binary zero). */
+
+ if (here > start && here[-1] == '\n') return start;
+
+ /* If we have not read a newline when reading a file, we have either filled
+ the buffer or reached the end of the file. We can detect the former by
+ checking that the string fills the buffer, and the latter by feof(). If
+ neither of these is true, it means we read a binary zero which has caused
+ strlen() to give a short length. This is a hard error because pcre2test
+ expects to work with C strings. */
+
+ if (!INTERACTIVE(f) && dlen < rlen - 1 && !feof(f))
+ {
+ fprintf(outfile, "** Binary zero encountered in input\n");
+ fprintf(outfile, "** pcre2test run abandoned\n");
+ exit(1);
+ }
+ }
+
+ else
+ {
+ size_t start_offset = start - buffer;
+ size_t here_offset = here - buffer;
+ expand_input_buffers();
+ start = buffer + start_offset;
+ here = buffer + here_offset;
+ }
+ }
+
+/* Control never gets here */
+}
+
+
+
+/*************************************************
+* Case-independent strncmp() function *
+*************************************************/
+
+/*
+Arguments:
+ s first string
+ t second string
+ n number of characters to compare
+
+Returns: < 0, = 0, or > 0, according to the comparison
+*/
+
+static int
+strncmpic(const uint8_t *s, const uint8_t *t, int n)
+{
+while (n--)
+ {
+ int c = tolower(*s++) - tolower(*t++);
+ if (c != 0) return c;
+ }
+return 0;
+}
+
+
+
+/*************************************************
+* Scan the main modifier list *
+*************************************************/
+
+/* This function searches the modifier list for a long modifier name.
+
+Argument:
+ p start of the name
+ lenp length of the name
+
+Returns: an index in the modifier list, or -1 on failure
+*/
+
+static int
+scan_modifiers(const uint8_t *p, unsigned int len)
+{
+int bot = 0;
+int top = MODLISTCOUNT;
+
+while (top > bot)
+ {
+ int mid = (bot + top)/2;
+ unsigned int mlen = strlen(modlist[mid].name);
+ int c = strncmp((char *)p, modlist[mid].name, (len < mlen)? len : mlen);
+ if (c == 0)
+ {
+ if (len == mlen) return mid;
+ c = (int)len - (int)mlen;
+ }
+ if (c > 0) bot = mid + 1; else top = mid;
+ }
+
+return -1;
+
+}
+
+
+
+/*************************************************
+* Check a modifer and find its field *
+*************************************************/
+
+/* This function is called when a modifier has been identified. We check that
+it is allowed here and find the field that is to be changed.
+
+Arguments:
+ m the modifier list entry
+ ctx CTX_PAT => pattern context
+ CTX_POPPAT => pattern context for popped pattern
+ CTX_DEFPAT => default pattern context
+ CTX_DAT => data context
+ CTX_DEFDAT => default data context
+ pctl point to pattern control block
+ dctl point to data control block
+ c a single character or 0
+
+Returns: a field pointer or NULL
+*/
+
+static void *
+check_modifier(modstruct *m, int ctx, patctl *pctl, datctl *dctl, uint32_t c)
+{
+void *field = NULL;
+PCRE2_SIZE offset = m->offset;
+
+if (restrict_for_perl_test) switch(m->which)
+ {
+ case MOD_PNDP:
+ case MOD_PATP:
+ case MOD_PDP:
+ break;
+
+ default:
+ fprintf(outfile, "** '%s' is not allowed in a Perl-compatible test\n",
+ m->name);
+ return NULL;
+ }
+
+switch (m->which)
+ {
+ case MOD_CTC: /* Compile context modifier */
+ if (ctx == CTX_DEFPAT) field = PTR(default_pat_context);
+ else if (ctx == CTX_PAT) field = PTR(pat_context);
+ break;
+
+ case MOD_CTM: /* Match context modifier */
+ if (ctx == CTX_DEFDAT) field = PTR(default_dat_context);
+ else if (ctx == CTX_DAT) field = PTR(dat_context);
+ break;
+
+ case MOD_DAT: /* Data line modifier */
+ if (dctl != NULL) field = dctl;
+ break;
+
+ case MOD_PAT: /* Pattern modifier */
+ case MOD_PATP: /* Allowed for Perl test */
+ if (pctl != NULL) field = pctl;
+ break;
+
+ case MOD_PD: /* Pattern or data line modifier */
+ case MOD_PDP: /* Ditto, allowed for Perl test */
+ case MOD_PND: /* Ditto, but not default pattern */
+ case MOD_PNDP: /* Ditto, allowed for Perl test */
+ if (dctl != NULL) field = dctl;
+ else if (pctl != NULL && (m->which == MOD_PD || m->which == MOD_PDP ||
+ ctx != CTX_DEFPAT))
+ field = pctl;
+ break;
+ }
+
+if (field == NULL)
+ {
+ if (c == 0)
+ fprintf(outfile, "** '%s' is not valid here\n", m->name);
+ else
+ fprintf(outfile, "** /%c is not valid here\n", c);
+ return NULL;
+ }
+
+return (char *)field + offset;
+}
+
+
+
+/*************************************************
+* Decode a modifier list *
+*************************************************/
+
+/* A pointer to a control block is NULL when called in cases when that block is
+not relevant. They are never all relevant in one call. At least one of patctl
+and datctl is NULL. The second argument specifies which context to use for
+modifiers that apply to contexts.
+
+Arguments:
+ p point to modifier string
+ ctx CTX_PAT => pattern context
+ CTX_POPPAT => pattern context for popped pattern
+ CTX_DEFPAT => default pattern context
+ CTX_DAT => data context
+ CTX_DEFDAT => default data context
+ pctl point to pattern control block
+ dctl point to data control block
+
+Returns: TRUE if successful decode, FALSE otherwise
+*/
+
+static BOOL
+decode_modifiers(uint8_t *p, int ctx, patctl *pctl, datctl *dctl)
+{
+uint8_t *ep, *pp;
+long li;
+unsigned long uli;
+BOOL first = TRUE;
+
+for (;;)
+ {
+ void *field;
+ modstruct *m;
+ BOOL off = FALSE;
+ unsigned int i, len;
+ int index;
+ char *endptr;
+
+ /* Skip white space and commas. */
+
+ while (isspace(*p) || *p == ',') p++;
+ if (*p == 0) break;
+
+ /* Find the end of the item; lose trailing whitespace at end of line. */
+
+ for (ep = p; *ep != 0 && *ep != ','; ep++);
+ if (*ep == 0)
+ {
+ while (ep > p && isspace(ep[-1])) ep--;
+ *ep = 0;
+ }
+
+ /* Remember if the first character is '-'. */
+
+ if (*p == '-')
+ {
+ off = TRUE;
+ p++;
+ }
+
+ /* Find the length of a full-length modifier name, and scan for it. */
+
+ pp = p;
+ while (pp < ep && *pp != '=') pp++;
+ index = scan_modifiers(p, pp - p);
+
+ /* If the first modifier is unrecognized, try to interpret it as a sequence
+ of single-character abbreviated modifiers. None of these modifiers have any
+ associated data. They just set options or control bits. */
+
+ if (index < 0)
+ {
+ uint32_t cc;
+ uint8_t *mp = p;
+
+ if (!first)
+ {
+ fprintf(outfile, "** Unrecognized modifier '%.*s'\n", (int)(ep-p), p);
+ if (ep - p == 1)
+ fprintf(outfile, "** Single-character modifiers must come first\n");
+ return FALSE;
+ }
+
+ for (cc = *p; cc != ',' && cc != '\n' && cc != 0; cc = *(++p))
+ {
+ for (i = 0; i < C1MODLISTCOUNT; i++)
+ if (cc == c1modlist[i].onechar) break;
+
+ if (i >= C1MODLISTCOUNT)
+ {
+ fprintf(outfile, "** Unrecognized modifier '%c' in '%.*s'\n",
+ *p, (int)(ep-mp), mp);
+ return FALSE;
+ }
+
+ if (c1modlist[i].index >= 0)
+ {
+ index = c1modlist[i].index;
+ }
+
+ else
+ {
+ index = scan_modifiers((uint8_t *)(c1modlist[i].fullname),
+ strlen(c1modlist[i].fullname));
+ if (index < 0)
+ {
+ fprintf(outfile, "** Internal error: single-character equivalent "
+ "modifier '%s' not found\n", c1modlist[i].fullname);
+ return FALSE;
+ }
+ c1modlist[i].index = index; /* Cache for next time */
+ }
+
+ field = check_modifier(modlist + index, ctx, pctl, dctl, *p);
+ if (field == NULL) return FALSE;
+
+ /* /x is a special case; a second appearance changes PCRE2_EXTENDED to
+ PCRE2_EXTENDED_MORE. */
+
+ if (cc == 'x' && (*((uint32_t *)field) & PCRE2_EXTENDED) != 0)
+ {
+ *((uint32_t *)field) &= ~PCRE2_EXTENDED;
+ *((uint32_t *)field) |= PCRE2_EXTENDED_MORE;
+ }
+ else
+ *((uint32_t *)field) |= modlist[index].value;
+ }
+
+ continue; /* With tne next (fullname) modifier */
+ }
+
+ /* We have a match on a full-name modifier. Check for the existence of data
+ when needed. */
+
+ m = modlist + index; /* Save typing */
+ if (m->type != MOD_CTL && m->type != MOD_OPT &&
+ (m->type != MOD_IND || *pp == '='))
+ {
+ if (*pp++ != '=')
+ {
+ fprintf(outfile, "** '=' expected after '%s'\n", m->name);
+ return FALSE;
+ }
+ if (off)
+ {
+ fprintf(outfile, "** '-' is not valid for '%s'\n", m->name);
+ return FALSE;
+ }
+ }
+
+ /* These on/off types have no data. */
+
+ else if (*pp != ',' && *pp != '\n' && *pp != ' ' && *pp != 0)
+ {
+ fprintf(outfile, "** Unrecognized modifier '%.*s'\n", (int)(ep-p), p);
+ return FALSE;
+ }
+
+ /* Set the data length for those types that have data. Then find the field
+ that is to be set. If check_modifier() returns NULL, it has already output an
+ error message. */
+
+ len = ep - pp;
+ field = check_modifier(m, ctx, pctl, dctl, 0);
+ if (field == NULL) return FALSE;
+
+ /* Process according to data type. */
+
+ switch (m->type)
+ {
+ case MOD_CTL:
+ case MOD_OPT:
+ if (off) *((uint32_t *)field) &= ~m->value;
+ else *((uint32_t *)field) |= m->value;
+ break;
+
+ case MOD_BSR:
+ if (len == 7 && strncmpic(pp, (const uint8_t *)"default", 7) == 0)
+ {
+#ifdef BSR_ANYCRLF
+ *((uint16_t *)field) = PCRE2_BSR_ANYCRLF;
+#else
+ *((uint16_t *)field) = PCRE2_BSR_UNICODE;
+#endif
+ if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 &= ~CTL2_BSR_SET;
+ else dctl->control2 &= ~CTL2_BSR_SET;
+ }
+ else
+ {
+ if (len == 7 && strncmpic(pp, (const uint8_t *)"anycrlf", 7) == 0)
+ *((uint16_t *)field) = PCRE2_BSR_ANYCRLF;
+ else if (len == 7 && strncmpic(pp, (const uint8_t *)"unicode", 7) == 0)
+ *((uint16_t *)field) = PCRE2_BSR_UNICODE;
+ else goto INVALID_VALUE;
+ if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 |= CTL2_BSR_SET;
+ else dctl->control2 |= CTL2_BSR_SET;
+ }
+ pp = ep;
+ break;
+
+ case MOD_CHR: /* A single character */
+ *((uint32_t *)field) = *pp++;
+ break;
+
+ case MOD_CON: /* A convert type/options list */
+ for (;; pp++)
+ {
+ uint8_t *colon = (uint8_t *)strchr((const char *)pp, ':');
+ len = ((colon != NULL && colon < ep)? colon:ep) - pp;
+ for (i = 0; i < convertlistcount; i++)
+ {
+ if (strncmpic(pp, (const uint8_t *)convertlist[i].name, len) == 0)
+ {
+ if (*((uint32_t *)field) == CONVERT_UNSET)
+ *((uint32_t *)field) = convertlist[i].option;
+ else
+ *((uint32_t *)field) |= convertlist[i].option;
+ break;
+ }
+ }
+ if (i >= convertlistcount) goto INVALID_VALUE;
+ pp += len;
+ if (*pp != ':') break;
+ }
+ break;
+
+ case MOD_IN2: /* One or two unsigned integers */
+ if (!isdigit(*pp)) goto INVALID_VALUE;
+ uli = strtoul((const char *)pp, &endptr, 10);
+ if (U32OVERFLOW(uli)) goto INVALID_VALUE;
+ ((uint32_t *)field)[0] = (uint32_t)uli;
+ if (*endptr == ':')
+ {
+ uli = strtoul((const char *)endptr+1, &endptr, 10);
+ if (U32OVERFLOW(uli)) goto INVALID_VALUE;
+ ((uint32_t *)field)[1] = (uint32_t)uli;
+ }
+ else ((uint32_t *)field)[1] = 0;
+ pp = (uint8_t *)endptr;
+ break;
+
+ /* PCRE2_SIZE_MAX is usually SIZE_MAX, which may be greater, equal to, or
+ less than ULONG_MAX. So first test for overflowing the long int, and then
+ test for overflowing PCRE2_SIZE_MAX if it is smaller than ULONG_MAX. */
+
+ case MOD_SIZ: /* PCRE2_SIZE value */
+ if (!isdigit(*pp)) goto INVALID_VALUE;
+ uli = strtoul((const char *)pp, &endptr, 10);
+ if (uli == ULONG_MAX) goto INVALID_VALUE;
+#if ULONG_MAX > PCRE2_SIZE_MAX
+ if (uli > PCRE2_SIZE_MAX) goto INVALID_VALUE;
+#endif
+ *((PCRE2_SIZE *)field) = (PCRE2_SIZE)uli;
+ pp = (uint8_t *)endptr;
+ break;
+
+ case MOD_IND: /* Unsigned integer with default */
+ if (len == 0)
+ {
+ *((uint32_t *)field) = (uint32_t)(m->value);
+ break;
+ }
+ /* Fall through */
+
+ case MOD_INT: /* Unsigned integer */
+ if (!isdigit(*pp)) goto INVALID_VALUE;
+ uli = strtoul((const char *)pp, &endptr, 10);
+ if (U32OVERFLOW(uli)) goto INVALID_VALUE;
+ *((uint32_t *)field) = (uint32_t)uli;
+ pp = (uint8_t *)endptr;
+ break;
+
+ case MOD_INS: /* Signed integer */
+ if (!isdigit(*pp) && *pp != '-') goto INVALID_VALUE;
+ li = strtol((const char *)pp, &endptr, 10);
+ if (S32OVERFLOW(li)) goto INVALID_VALUE;
+ *((int32_t *)field) = (int32_t)li;
+ pp = (uint8_t *)endptr;
+ break;
+
+ case MOD_NL:
+ for (i = 0; i < sizeof(newlines)/sizeof(char *); i++)
+ if (len == strlen(newlines[i]) &&
+ strncmpic(pp, (const uint8_t *)newlines[i], len) == 0) break;
+ if (i >= sizeof(newlines)/sizeof(char *)) goto INVALID_VALUE;
+ if (i == 0)
+ {
+ *((uint16_t *)field) = NEWLINE_DEFAULT;
+ if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 &= ~CTL2_NL_SET;
+ else dctl->control2 &= ~CTL2_NL_SET;
+ }
+ else
+ {
+ *((uint16_t *)field) = i;
+ if (ctx == CTX_PAT || ctx == CTX_DEFPAT) pctl->control2 |= CTL2_NL_SET;
+ else dctl->control2 |= CTL2_NL_SET;
+ }
+ pp = ep;
+ break;
+
+ case MOD_NN: /* Name or (signed) number; may be several */
+ if (isdigit(*pp) || *pp == '-')
+ {
+ int ct = MAXCPYGET - 1;
+ int32_t value;
+ li = strtol((const char *)pp, &endptr, 10);
+ if (S32OVERFLOW(li)) goto INVALID_VALUE;
+ value = (int32_t)li;
+ field = (char *)field - m->offset + m->value; /* Adjust field ptr */
+ if (value >= 0) /* Add new number */
+ {
+ while (*((int32_t *)field) >= 0 && ct-- > 0) /* Skip previous */
+ field = (char *)field + sizeof(int32_t);
+ if (ct <= 0)
+ {
+ fprintf(outfile, "** Too many numeric '%s' modifiers\n", m->name);
+ return FALSE;
+ }
+ }
+ *((int32_t *)field) = value;
+ if (ct > 0) ((int32_t *)field)[1] = -1;
+ pp = (uint8_t *)endptr;
+ }
+
+ /* Multiple strings are put end to end. */
+
+ else
+ {
+ char *nn = (char *)field;
+ if (len > 0) /* Add new name */
+ {
+ if (len > MAX_NAME_SIZE)
+ {
+ fprintf(outfile, "** Group name in '%s' is too long\n", m->name);
+ return FALSE;
+ }
+ while (*nn != 0) nn += strlen(nn) + 1;
+ if (nn + len + 2 - (char *)field > LENCPYGET)
+ {
+ fprintf(outfile, "** Too many characters in named '%s' modifiers\n",
+ m->name);
+ return FALSE;
+ }
+ memcpy(nn, pp, len);
+ }
+ nn[len] = 0 ;
+ nn[len+1] = 0;
+ pp = ep;
+ }
+ break;
+
+ case MOD_STR:
+ if (len + 1 > m->value)
+ {
+ fprintf(outfile, "** Overlong value for '%s' (max %d code units)\n",
+ m->name, m->value - 1);
+ return FALSE;
+ }
+ memcpy(field, pp, len);
+ ((uint8_t *)field)[len] = 0;
+ pp = ep;
+ break;
+ }
+
+ if (*pp != ',' && *pp != '\n' && *pp != ' ' && *pp != 0)
+ {
+ fprintf(outfile, "** Comma expected after modifier item '%s'\n", m->name);
+ return FALSE;
+ }
+
+ p = pp;
+ first = FALSE;
+
+ if (ctx == CTX_POPPAT &&
+ (pctl->options != 0 ||
+ pctl->tables_id != 0 ||
+ pctl->locale[0] != 0 ||
+ (pctl->control & NOTPOP_CONTROLS) != 0))
+ {
+ fprintf(outfile, "** '%s' is not valid here\n", m->name);
+ return FALSE;
+ }
+ }
+
+return TRUE;
+
+INVALID_VALUE:
+fprintf(outfile, "** Invalid value in '%.*s'\n", (int)(ep-p), p);
+return FALSE;
+}
+
+
+/*************************************************
+* Get info from a pattern *
+*************************************************/
+
+/* A wrapped call to pcre2_pattern_info(), applied to the current compiled
+pattern.
+
+Arguments:
+ what code for the required information
+ where where to put the answer
+ unsetok PCRE2_ERROR_UNSET is an "expected" result
+
+Returns: the return from pcre2_pattern_info()
+*/
+
+static int
+pattern_info(int what, void *where, BOOL unsetok)
+{
+int rc;
+PCRE2_PATTERN_INFO(rc, compiled_code, what, NULL); /* Exercise the code */
+PCRE2_PATTERN_INFO(rc, compiled_code, what, where);
+if (rc >= 0) return 0;
+if (rc != PCRE2_ERROR_UNSET || !unsetok)
+ {
+ fprintf(outfile, "Error %d from pcre2_pattern_info_%d(%d)\n", rc, test_mode,
+ what);
+ if (rc == PCRE2_ERROR_BADMODE)
+ fprintf(outfile, "Running in %d-bit mode but pattern was compiled in "
+ "%d-bit mode\n", test_mode,
+ 8 * (FLD(compiled_code, flags) & PCRE2_MODE_MASK));
+ }
+return rc;
+}
+
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+* Show something in a list *
+*************************************************/
+
+/* This function just helps to keep the code that uses it tidier. It's used for
+various lists of things where there needs to be introductory text before the
+first item. As these calls are all in the POSIX-support code, they happen only
+when 8-bit mode is supported. */
+
+static void
+prmsg(const char **msg, const char *s)
+{
+fprintf(outfile, "%s %s", *msg, s);
+*msg = "";
+}
+#endif /* SUPPORT_PCRE2_8 */
+
+
+
+/*************************************************
+* Show control bits *
+*************************************************/
+
+/* Called for mutually exclusive controls and for unsupported POSIX controls.
+Because the bits are unique, this can be used for both pattern and data control
+words.
+
+Arguments:
+ controls control bits
+ controls2 more control bits
+ before text to print before
+
+Returns: nothing
+*/
+
+static void
+show_controls(uint32_t controls, uint32_t controls2, const char *before)
+{
+fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ before,
+ ((controls & CTL_AFTERTEXT) != 0)? " aftertext" : "",
+ ((controls & CTL_ALLAFTERTEXT) != 0)? " allaftertext" : "",
+ ((controls & CTL_ALLCAPTURES) != 0)? " allcaptures" : "",
+ ((controls & CTL_ALLUSEDTEXT) != 0)? " allusedtext" : "",
+ ((controls & CTL_ALTGLOBAL) != 0)? " altglobal" : "",
+ ((controls & CTL_BINCODE) != 0)? " bincode" : "",
+ ((controls2 & CTL2_BSR_SET) != 0)? " bsr" : "",
+ ((controls & CTL_CALLOUT_CAPTURE) != 0)? " callout_capture" : "",
+ ((controls2 & CTL2_CALLOUT_EXTRA) != 0)? " callout_extra" : "",
+ ((controls & CTL_CALLOUT_INFO) != 0)? " callout_info" : "",
+ ((controls & CTL_CALLOUT_NONE) != 0)? " callout_none" : "",
+ ((controls2 & CTL2_CALLOUT_NO_WHERE) != 0)? " callout_no_where" : "",
+ ((controls & CTL_DFA) != 0)? " dfa" : "",
+ ((controls & CTL_EXPAND) != 0)? " expand" : "",
+ ((controls & CTL_FINDLIMITS) != 0)? " find_limits" : "",
+ ((controls & CTL_FRAMESIZE) != 0)? " framesize" : "",
+ ((controls & CTL_FULLBINCODE) != 0)? " fullbincode" : "",
+ ((controls & CTL_GETALL) != 0)? " getall" : "",
+ ((controls & CTL_GLOBAL) != 0)? " global" : "",
+ ((controls & CTL_HEXPAT) != 0)? " hex" : "",
+ ((controls & CTL_INFO) != 0)? " info" : "",
+ ((controls & CTL_JITFAST) != 0)? " jitfast" : "",
+ ((controls & CTL_JITVERIFY) != 0)? " jitverify" : "",
+ ((controls & CTL_MARK) != 0)? " mark" : "",
+ ((controls & CTL_MEMORY) != 0)? " memory" : "",
+ ((controls2 & CTL2_NL_SET) != 0)? " newline" : "",
+ ((controls & CTL_NULLCONTEXT) != 0)? " null_context" : "",
+ ((controls & CTL_POSIX) != 0)? " posix" : "",
+ ((controls & CTL_POSIX_NOSUB) != 0)? " posix_nosub" : "",
+ ((controls & CTL_PUSH) != 0)? " push" : "",
+ ((controls & CTL_PUSHCOPY) != 0)? " pushcopy" : "",
+ ((controls & CTL_PUSHTABLESCOPY) != 0)? " pushtablescopy" : "",
+ ((controls & CTL_STARTCHAR) != 0)? " startchar" : "",
+ ((controls2 & CTL2_SUBSTITUTE_EXTENDED) != 0)? " substitute_extended" : "",
+ ((controls2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)? " substitute_overflow_length" : "",
+ ((controls2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) != 0)? " substitute_unknown_unset" : "",
+ ((controls2 & CTL2_SUBSTITUTE_UNSET_EMPTY) != 0)? " substitute_unset_empty" : "",
+ ((controls & CTL_USE_LENGTH) != 0)? " use_length" : "",
+ ((controls & CTL_UTF8_INPUT) != 0)? " utf8_input" : "",
+ ((controls & CTL_ZERO_TERMINATE) != 0)? " zero_terminate" : "");
+}
+
+
+
+/*************************************************
+* Show compile options *
+*************************************************/
+
+/* Called from show_pattern_info() and for unsupported POSIX options.
+
+Arguments:
+ options an options word
+ before text to print before
+ after text to print after
+
+Returns: nothing
+*/
+
+static void
+show_compile_options(uint32_t options, const char *before, const char *after)
+{
+if (options == 0) fprintf(outfile, "%s <none>%s", before, after);
+else fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ before,
+ ((options & PCRE2_ALT_BSUX) != 0)? " alt_bsux" : "",
+ ((options & PCRE2_ALT_CIRCUMFLEX) != 0)? " alt_circumflex" : "",
+ ((options & PCRE2_ALT_VERBNAMES) != 0)? " alt_verbnames" : "",
+ ((options & PCRE2_ALLOW_EMPTY_CLASS) != 0)? " allow_empty_class" : "",
+ ((options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+ ((options & PCRE2_AUTO_CALLOUT) != 0)? " auto_callout" : "",
+ ((options & PCRE2_CASELESS) != 0)? " caseless" : "",
+ ((options & PCRE2_DOLLAR_ENDONLY) != 0)? " dollar_endonly" : "",
+ ((options & PCRE2_DOTALL) != 0)? " dotall" : "",
+ ((options & PCRE2_DUPNAMES) != 0)? " dupnames" : "",
+ ((options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+ ((options & PCRE2_EXTENDED) != 0)? " extended" : "",
+ ((options & PCRE2_EXTENDED_MORE) != 0)? " extended_more" : "",
+ ((options & PCRE2_FIRSTLINE) != 0)? " firstline" : "",
+ ((options & PCRE2_LITERAL) != 0)? " literal" : "",
+ ((options & PCRE2_MATCH_UNSET_BACKREF) != 0)? " match_unset_backref" : "",
+ ((options & PCRE2_MULTILINE) != 0)? " multiline" : "",
+ ((options & PCRE2_NEVER_BACKSLASH_C) != 0)? " never_backslash_c" : "",
+ ((options & PCRE2_NEVER_UCP) != 0)? " never_ucp" : "",
+ ((options & PCRE2_NEVER_UTF) != 0)? " never_utf" : "",
+ ((options & PCRE2_NO_AUTO_CAPTURE) != 0)? " no_auto_capture" : "",
+ ((options & PCRE2_NO_AUTO_POSSESS) != 0)? " no_auto_possess" : "",
+ ((options & PCRE2_NO_DOTSTAR_ANCHOR) != 0)? " no_dotstar_anchor" : "",
+ ((options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+ ((options & PCRE2_NO_START_OPTIMIZE) != 0)? " no_start_optimize" : "",
+ ((options & PCRE2_UCP) != 0)? " ucp" : "",
+ ((options & PCRE2_UNGREEDY) != 0)? " ungreedy" : "",
+ ((options & PCRE2_USE_OFFSET_LIMIT) != 0)? " use_offset_limit" : "",
+ ((options & PCRE2_UTF) != 0)? " utf" : "",
+ after);
+}
+
+
+/*************************************************
+* Show compile extra options *
+*************************************************/
+
+/* Called from show_pattern_info() and for unsupported POSIX options.
+
+Arguments:
+ options an options word
+ before text to print before
+ after text to print after
+
+Returns: nothing
+*/
+
+static void
+show_compile_extra_options(uint32_t options, const char *before,
+ const char *after)
+{
+if (options == 0) fprintf(outfile, "%s <none>%s", before, after);
+else fprintf(outfile, "%s%s%s%s%s%s",
+ before,
+ ((options & PCRE2_EXTRA_ALLOW_SURROGATE_ESCAPES) != 0)? " allow_surrogate_escapes" : "",
+ ((options & PCRE2_EXTRA_BAD_ESCAPE_IS_LITERAL) != 0)? " bad_escape_is_literal" : "",
+ ((options & PCRE2_EXTRA_MATCH_WORD) != 0)? " match_word" : "",
+ ((options & PCRE2_EXTRA_MATCH_LINE) != 0)? " match_line" : "",
+ after);
+}
+
+
+
+#ifdef SUPPORT_PCRE2_8
+/*************************************************
+* Show match options *
+*************************************************/
+
+/* Called for unsupported POSIX options. */
+
+static void
+show_match_options(uint32_t options)
+{
+fprintf(outfile, "%s%s%s%s%s%s%s%s%s%s%s",
+ ((options & PCRE2_ANCHORED) != 0)? " anchored" : "",
+ ((options & PCRE2_DFA_RESTART) != 0)? " dfa_restart" : "",
+ ((options & PCRE2_DFA_SHORTEST) != 0)? " dfa_shortest" : "",
+ ((options & PCRE2_ENDANCHORED) != 0)? " endanchored" : "",
+ ((options & PCRE2_NO_UTF_CHECK) != 0)? " no_utf_check" : "",
+ ((options & PCRE2_NOTBOL) != 0)? " notbol" : "",
+ ((options & PCRE2_NOTEMPTY) != 0)? " notempty" : "",
+ ((options & PCRE2_NOTEMPTY_ATSTART) != 0)? " notempty_atstart" : "",
+ ((options & PCRE2_NOTEOL) != 0)? " noteol" : "",
+ ((options & PCRE2_PARTIAL_HARD) != 0)? " partial_hard" : "",
+ ((options & PCRE2_PARTIAL_SOFT) != 0)? " partial_soft" : "");
+}
+#endif /* SUPPORT_PCRE2_8 */
+
+
+
+/*************************************************
+* Show memory usage info for a pattern *
+*************************************************/
+
+static void
+show_memory_info(void)
+{
+uint32_t name_count, name_entry_size;
+size_t size, cblock_size;
+
+/* One of the test_mode values will always be true, but to stop a compiler
+warning we must initialize cblock_size. */
+
+cblock_size = 0;
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE) cblock_size = sizeof(pcre2_real_code_8);
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE) cblock_size = sizeof(pcre2_real_code_16);
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE) cblock_size = sizeof(pcre2_real_code_32);
+#endif
+
+(void)pattern_info(PCRE2_INFO_SIZE, &size, FALSE);
+(void)pattern_info(PCRE2_INFO_NAMECOUNT, &name_count, FALSE);
+(void)pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &name_entry_size, FALSE);
+fprintf(outfile, "Memory allocation (code space): %d\n",
+ (int)(size - name_count*name_entry_size*code_unit_size - cblock_size));
+if (pat_patctl.jit != 0)
+ {
+ (void)pattern_info(PCRE2_INFO_JITSIZE, &size, FALSE);
+ fprintf(outfile, "Memory allocation (JIT code): %d\n", (int)size);
+ }
+}
+
+
+
+/*************************************************
+* Show frame size info for a pattern *
+*************************************************/
+
+static void
+show_framesize(void)
+{
+size_t frame_size;
+(void)pattern_info(PCRE2_INFO_FRAMESIZE, &frame_size, FALSE);
+fprintf(outfile, "Frame size for pcre2_match(): %d\n", (int)frame_size);
+}
+
+
+
+/*************************************************
+* Get and output an error message *
+*************************************************/
+
+static BOOL
+print_error_message(int errorcode, const char *before, const char *after)
+{
+int len;
+PCRE2_GET_ERROR_MESSAGE(len, errorcode, pbuffer);
+if (len < 0)
+ {
+ fprintf(outfile, "\n** pcre2test internal error: cannot interpret error "
+ "number\n** Unexpected return (%d) from pcre2_get_error_message()\n", len);
+ }
+else
+ {
+ fprintf(outfile, "%s", before);
+ PCHARSV(CASTVAR(void *, pbuffer), 0, len, FALSE, outfile);
+ fprintf(outfile, "%s", after);
+ }
+return len >= 0;
+}
+
+
+/*************************************************
+* Callback function for callout enumeration *
+*************************************************/
+
+/* The only differences in the callout emumeration block for different code
+unit widths are that the pointers to the subject, the most recent MARK, and a
+callout argument string point to strings of the appropriate width. Casts can be
+used to deal with this.
+
+Argument:
+ cb pointer to enumerate block
+ callout_data user data
+
+Returns: 0
+*/
+
+static int callout_callback(pcre2_callout_enumerate_block_8 *cb,
+ void *callout_data)
+{
+uint32_t i;
+BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+
+(void)callout_data; /* Not currently displayed */
+
+fprintf(outfile, "Callout ");
+if (cb->callout_string != NULL)
+ {
+ uint32_t delimiter = CODE_UNIT(cb->callout_string, -1);
+ fprintf(outfile, "%c", delimiter);
+ PCHARSV(cb->callout_string, 0,
+ cb->callout_string_length, utf, outfile);
+ for (i = 0; callout_start_delims[i] != 0; i++)
+ if (delimiter == callout_start_delims[i])
+ {
+ delimiter = callout_end_delims[i];
+ break;
+ }
+ fprintf(outfile, "%c ", delimiter);
+ }
+else fprintf(outfile, "%d ", cb->callout_number);
+
+fprintf(outfile, "%.*s\n",
+ (int)((cb->next_item_length == 0)? 1 : cb->next_item_length),
+ pbuffer8 + cb->pattern_position);
+
+return 0;
+}
+
+
+
+/*************************************************
+* Show information about a pattern *
+*************************************************/
+
+/* This function is called after a pattern has been compiled if any of the
+information-requesting controls have been set.
+
+Arguments: none
+
+Returns: PR_OK continue processing next line
+ PR_SKIP skip to a blank line
+ PR_ABEND abort the pcre2test run
+*/
+
+static int
+show_pattern_info(void)
+{
+uint32_t compile_options, overall_options, extra_options;
+
+if ((pat_patctl.control & (CTL_BINCODE|CTL_FULLBINCODE)) != 0)
+ {
+ fprintf(outfile, "------------------------------------------------------------------\n");
+ PCRE2_PRINTINT((pat_patctl.control & CTL_FULLBINCODE) != 0);
+ }
+
+if ((pat_patctl.control & CTL_INFO) != 0)
+ {
+ int rc;
+ void *nametable;
+ uint8_t *start_bits;
+ BOOL heap_limit_set, match_limit_set, depth_limit_set;
+ uint32_t backrefmax, bsr_convention, capture_count, first_ctype, first_cunit,
+ hasbackslashc, hascrorlf, jchanged, last_ctype, last_cunit, match_empty,
+ depth_limit, heap_limit, match_limit, minlength, nameentrysize, namecount,
+ newline_convention;
+
+ /* Exercise the error route. */
+
+ PCRE2_PATTERN_INFO(rc, compiled_code, 999, NULL);
+ (void)rc;
+
+ /* These info requests may return PCRE2_ERROR_UNSET. */
+
+ switch(pattern_info(PCRE2_INFO_HEAPLIMIT, &heap_limit, TRUE))
+ {
+ case 0:
+ heap_limit_set = TRUE;
+ break;
+
+ case PCRE2_ERROR_UNSET:
+ heap_limit_set = FALSE;
+ break;
+
+ default:
+ return PR_ABEND;
+ }
+
+ switch(pattern_info(PCRE2_INFO_MATCHLIMIT, &match_limit, TRUE))
+ {
+ case 0:
+ match_limit_set = TRUE;
+ break;
+
+ case PCRE2_ERROR_UNSET:
+ match_limit_set = FALSE;
+ break;
+
+ default:
+ return PR_ABEND;
+ }
+
+ switch(pattern_info(PCRE2_INFO_DEPTHLIMIT, &depth_limit, TRUE))
+ {
+ case 0:
+ depth_limit_set = TRUE;
+ break;
+
+ case PCRE2_ERROR_UNSET:
+ depth_limit_set = FALSE;
+ break;
+
+ default:
+ return PR_ABEND;
+ }
+
+ /* These info requests should always succeed. */
+
+ if (pattern_info(PCRE2_INFO_BACKREFMAX, &backrefmax, FALSE) +
+ pattern_info(PCRE2_INFO_BSR, &bsr_convention, FALSE) +
+ pattern_info(PCRE2_INFO_CAPTURECOUNT, &capture_count, FALSE) +
+ pattern_info(PCRE2_INFO_FIRSTBITMAP, &start_bits, FALSE) +
+ pattern_info(PCRE2_INFO_FIRSTCODEUNIT, &first_cunit, FALSE) +
+ pattern_info(PCRE2_INFO_FIRSTCODETYPE, &first_ctype, FALSE) +
+ pattern_info(PCRE2_INFO_HASBACKSLASHC, &hasbackslashc, FALSE) +
+ pattern_info(PCRE2_INFO_HASCRORLF, &hascrorlf, FALSE) +
+ pattern_info(PCRE2_INFO_JCHANGED, &jchanged, FALSE) +
+ pattern_info(PCRE2_INFO_LASTCODEUNIT, &last_cunit, FALSE) +
+ pattern_info(PCRE2_INFO_LASTCODETYPE, &last_ctype, FALSE) +
+ pattern_info(PCRE2_INFO_MATCHEMPTY, &match_empty, FALSE) +
+ pattern_info(PCRE2_INFO_MINLENGTH, &minlength, FALSE) +
+ pattern_info(PCRE2_INFO_NAMECOUNT, &namecount, FALSE) +
+ pattern_info(PCRE2_INFO_NAMEENTRYSIZE, &nameentrysize, FALSE) +
+ pattern_info(PCRE2_INFO_NAMETABLE, &nametable, FALSE) +
+ pattern_info(PCRE2_INFO_NEWLINE, &newline_convention, FALSE)
+ != 0)
+ return PR_ABEND;
+
+ fprintf(outfile, "Capturing subpattern count = %d\n", capture_count);
+
+ if (backrefmax > 0)
+ fprintf(outfile, "Max back reference = %d\n", backrefmax);
+
+ if (maxlookbehind > 0)
+ fprintf(outfile, "Max lookbehind = %d\n", maxlookbehind);
+
+ if (heap_limit_set)
+ fprintf(outfile, "Heap limit = %u\n", heap_limit);
+
+ if (match_limit_set)
+ fprintf(outfile, "Match limit = %u\n", match_limit);
+
+ if (depth_limit_set)
+ fprintf(outfile, "Depth limit = %u\n", depth_limit);
+
+ if (namecount > 0)
+ {
+ fprintf(outfile, "Named capturing subpatterns:\n");
+ for (; namecount > 0; namecount--)
+ {
+ int imm2_size = test_mode == PCRE8_MODE ? 2 : 1;
+ uint32_t length = (uint32_t)STRLEN(nametable + imm2_size);
+ fprintf(outfile, " ");
+ PCHARSV(nametable, imm2_size, length, FALSE, outfile);
+ while (length++ < nameentrysize - imm2_size) putc(' ', outfile);
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE)
+ fprintf(outfile, "%3d\n", (int)(((PCRE2_SPTR32)nametable)[0]));
+#endif
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE)
+ fprintf(outfile, "%3d\n", (int)(((PCRE2_SPTR16)nametable)[0]));
+#endif
+#ifdef SUPPORT_PCRE2_8
+ if (test_mode == PCRE8_MODE)
+ fprintf(outfile, "%3d\n", (int)(
+ ((((PCRE2_SPTR8)nametable)[0]) << 8) | ((PCRE2_SPTR8)nametable)[1]));
+#endif
+ nametable = (void*)((PCRE2_SPTR8)nametable + nameentrysize * code_unit_size);
+ }
+ }
+
+ if (hascrorlf) fprintf(outfile, "Contains explicit CR or LF match\n");
+ if (hasbackslashc) fprintf(outfile, "Contains \\C\n");
+ if (match_empty) fprintf(outfile, "May match empty string\n");
+
+ pattern_info(PCRE2_INFO_ARGOPTIONS, &compile_options, FALSE);
+ pattern_info(PCRE2_INFO_ALLOPTIONS, &overall_options, FALSE);
+ pattern_info(PCRE2_INFO_EXTRAOPTIONS, &extra_options, FALSE);
+
+ /* Remove UTF/UCP if they were there only because of forbid_utf. This saves
+ cluttering up the verification output of non-UTF test files. */
+
+ if ((pat_patctl.options & PCRE2_NEVER_UTF) == 0)
+ {
+ compile_options &= ~PCRE2_NEVER_UTF;
+ overall_options &= ~PCRE2_NEVER_UTF;
+ }
+
+ if ((pat_patctl.options & PCRE2_NEVER_UCP) == 0)
+ {
+ compile_options &= ~PCRE2_NEVER_UCP;
+ overall_options &= ~PCRE2_NEVER_UCP;
+ }
+
+ if ((compile_options|overall_options) != 0)
+ {
+ if (compile_options == overall_options)
+ show_compile_options(compile_options, "Options:", "\n");
+ else
+ {
+ show_compile_options(compile_options, "Compile options:", "\n");
+ show_compile_options(overall_options, "Overall options:", "\n");
+ }
+ }
+
+ if (extra_options != 0)
+ show_compile_extra_options(extra_options, "Extra options:", "\n");
+
+ if (jchanged) fprintf(outfile, "Duplicate name status changes\n");
+
+ if ((pat_patctl.control2 & CTL2_BSR_SET) != 0 ||
+ (FLD(compiled_code, flags) & PCRE2_BSR_SET) != 0)
+ fprintf(outfile, "\\R matches %s\n", (bsr_convention == PCRE2_BSR_UNICODE)?
+ "any Unicode newline" : "CR, LF, or CRLF");
+
+ if ((FLD(compiled_code, flags) & PCRE2_NL_SET) != 0)
+ {
+ switch (newline_convention)
+ {
+ case PCRE2_NEWLINE_CR:
+ fprintf(outfile, "Forced newline is CR\n");
+ break;
+
+ case PCRE2_NEWLINE_LF:
+ fprintf(outfile, "Forced newline is LF\n");
+ break;
+
+ case PCRE2_NEWLINE_CRLF:
+ fprintf(outfile, "Forced newline is CRLF\n");
+ break;
+
+ case PCRE2_NEWLINE_ANYCRLF:
+ fprintf(outfile, "Forced newline is CR, LF, or CRLF\n");
+ break;
+
+ case PCRE2_NEWLINE_ANY:
+ fprintf(outfile, "Forced newline is any Unicode newline\n");
+ break;
+
+ case PCRE2_NEWLINE_NUL:
+ fprintf(outfile, "Forced newline is NUL\n");
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (first_ctype == 2)
+ {
+ fprintf(outfile, "First code unit at start or follows newline\n");
+ }
+ else if (first_ctype == 1)
+ {
+ const char *caseless =
+ ((FLD(compiled_code, flags) & PCRE2_FIRSTCASELESS) == 0)?
+ "" : " (caseless)";
+ if (PRINTOK(first_cunit))
+ fprintf(outfile, "First code unit = \'%c\'%s\n", first_cunit, caseless);
+ else
+ {
+ fprintf(outfile, "First code unit = ");
+ pchar(first_cunit, FALSE, outfile);
+ fprintf(outfile, "%s\n", caseless);
+ }
+ }
+ else if (start_bits != NULL)
+ {
+ int i;
+ int c = 24;
+ fprintf(outfile, "Starting code units: ");
+ for (i = 0; i < 256; i++)
+ {
+ if ((start_bits[i/8] & (1<<(i&7))) != 0)
+ {
+ if (c > 75)
+ {
+ fprintf(outfile, "\n ");
+ c = 2;
+ }
+ if (PRINTOK(i) && i != ' ')
+ {
+ fprintf(outfile, "%c ", i);
+ c += 2;
+ }
+ else
+ {
+ fprintf(outfile, "\\x%02x ", i);
+ c += 5;
+ }
+ }
+ }
+ fprintf(outfile, "\n");
+ }
+
+ if (last_ctype != 0)
+ {
+ const char *caseless =
+ ((FLD(compiled_code, flags) & PCRE2_LASTCASELESS) == 0)?
+ "" : " (caseless)";
+ if (PRINTOK(last_cunit))
+ fprintf(outfile, "Last code unit = \'%c\'%s\n", last_cunit, caseless);
+ else
+ {
+ fprintf(outfile, "Last code unit = ");
+ pchar(last_cunit, FALSE, outfile);
+ fprintf(outfile, "%s\n", caseless);
+ }
+ }
+
+ fprintf(outfile, "Subject length lower bound = %d\n", minlength);
+
+ if (pat_patctl.jit != 0 && (pat_patctl.control & CTL_JITVERIFY) != 0)
+ {
+ if (FLD(compiled_code, executable_jit) != NULL)
+ fprintf(outfile, "JIT compilation was successful\n");
+ else
+ {
+#ifdef SUPPORT_JIT
+ fprintf(outfile, "JIT compilation was not successful");
+ if (jitrc != 0 && !print_error_message(jitrc, " (", ")"))
+ return PR_ABEND;
+ fprintf(outfile, "\n");
+#else
+ fprintf(outfile, "JIT support is not available in this version of PCRE2\n");
+#endif
+ }
+ }
+ }
+
+if ((pat_patctl.control & CTL_CALLOUT_INFO) != 0)
+ {
+ int errorcode;
+ PCRE2_CALLOUT_ENUMERATE(errorcode, callout_callback, 0);
+ if (errorcode != 0)
+ {
+ fprintf(outfile, "Callout enumerate failed: error %d: ", errorcode);
+ if (errorcode < 0 && !print_error_message(errorcode, "", "\n"))
+ return PR_ABEND;
+ return PR_SKIP;
+ }
+ }
+
+return PR_OK;
+}
+
+
+
+/*************************************************
+* Handle serialization error *
+*************************************************/
+
+/* Print an error message after a serialization failure.
+
+Arguments:
+ rc the error code
+ msg an initial message for what failed
+
+Returns: FALSE if print_error_message() fails
+*/
+
+static BOOL
+serial_error(int rc, const char *msg)
+{
+fprintf(outfile, "%s failed: error %d: ", msg, rc);
+return print_error_message(rc, "", "\n");
+}
+
+
+
+/*************************************************
+* Open file for save/load commands *
+*************************************************/
+
+/* This function decodes the file name and opens the file.
+
+Arguments:
+ buffptr point after the #command
+ mode open mode
+ fptr points to the FILE variable
+
+Returns: PR_OK or PR_ABEND
+*/
+
+static int
+open_file(uint8_t *buffptr, const char *mode, FILE **fptr)
+{
+char *endf;
+char *filename = (char *)buffptr;
+while (isspace(*filename)) filename++;
+endf = filename + strlen8(filename);
+while (endf > filename && isspace(endf[-1])) endf--;
+
+if (endf == filename)
+ {
+ fprintf(outfile, "** File name expected after #save\n");
+ return PR_ABEND;
+ }
+
+*endf = 0;
+*fptr = fopen((const char *)filename, mode);
+if (*fptr == NULL)
+ {
+ fprintf(outfile, "** Failed to open '%s': %s\n", filename, strerror(errno));
+ return PR_ABEND;
+ }
+
+return PR_OK;
+}
+
+
+
+/*************************************************
+* Process command line *
+*************************************************/
+
+/* This function is called for lines beginning with # and a character that is
+not ! or whitespace, when encountered between tests, which means that there is
+no compiled pattern (compiled_code is NULL). The line is in buffer.
+
+Arguments: none
+
+Returns: PR_OK continue processing next line
+ PR_SKIP skip to a blank line
+ PR_ABEND abort the pcre2test run
+*/
+
+static int
+process_command(void)
+{
+FILE *f;
+PCRE2_SIZE serial_size;
+size_t i;
+int rc, cmd, cmdlen, yield;
+uint16_t first_listed_newline;
+const char *cmdname;
+uint8_t *argptr, *serial;
+
+yield = PR_OK;
+cmd = CMD_UNKNOWN;
+cmdlen = 0;
+
+for (i = 0; i < cmdlistcount; i++)
+ {
+ cmdname = cmdlist[i].name;
+ cmdlen = strlen(cmdname);
+ if (strncmp((char *)(buffer+1), cmdname, cmdlen) == 0 &&
+ isspace(buffer[cmdlen+1]))
+ {
+ cmd = cmdlist[i].value;
+ break;
+ }
+ }
+
+argptr = buffer + cmdlen + 1;
+
+if (restrict_for_perl_test && cmd != CMD_PATTERN && cmd != CMD_SUBJECT)
+ {
+ fprintf(outfile, "** #%s is not allowed after #perltest\n", cmdname);
+ return PR_ABEND;
+ }
+
+switch(cmd)
+ {
+ case CMD_UNKNOWN:
+ fprintf(outfile, "** Unknown command: %s", buffer);
+ break;
+
+ case CMD_FORBID_UTF:
+ forbid_utf = PCRE2_NEVER_UTF|PCRE2_NEVER_UCP;
+ break;
+
+ case CMD_PERLTEST:
+ restrict_for_perl_test = TRUE;
+ break;
+
+ /* Set default pattern modifiers */
+
+ case CMD_PATTERN:
+ (void)decode_modifiers(argptr, CTX_DEFPAT, &def_patctl, NULL);
+ if (def_patctl.jit == 0 && (def_patctl.control & CTL_JITVERIFY) != 0)
+ def_patctl.jit = 7;
+ break;
+
+ /* Set default subject modifiers */
+
+ case CMD_SUBJECT:
+ (void)decode_modifiers(argptr, CTX_DEFDAT, NULL, &def_datctl);
+ break;
+
+ /* Check the default newline, and if not one of those listed, set up the
+ first one to be forced. An empty list unsets. */
+
+ case CMD_NEWLINE_DEFAULT:
+ local_newline_default = 0; /* Unset */
+ first_listed_newline = 0;
+ for (;;)
+ {
+ while (isspace(*argptr)) argptr++;
+ if (*argptr == 0) break;
+ for (i = 1; i < sizeof(newlines)/sizeof(char *); i++)
+ {
+ size_t nlen = strlen(newlines[i]);
+ if (strncmpic(argptr, (const uint8_t *)newlines[i], nlen) == 0 &&
+ isspace(argptr[nlen]))
+ {
+ if (i == NEWLINE_DEFAULT) return PR_OK; /* Default is valid */
+ if (first_listed_newline == 0) first_listed_newline = i;
+ }
+ }
+ while (*argptr != 0 && !isspace(*argptr)) argptr++;
+ }
+ local_newline_default = first_listed_newline;
+ break;
+
+ /* Pop or copy a compiled pattern off the stack. Modifiers that do not affect
+ the compiled pattern (e.g. to give information) are permitted. The default
+ pattern modifiers are ignored. */
+
+ case CMD_POP:
+ case CMD_POPCOPY:
+ if (patstacknext <= 0)
+ {
+ fprintf(outfile, "** Can't pop off an empty stack\n");
+ return PR_SKIP;
+ }
+ memset(&pat_patctl, 0, sizeof(patctl)); /* Completely unset */
+ if (!decode_modifiers(argptr, CTX_POPPAT, &pat_patctl, NULL))
+ return PR_SKIP;
+
+ if (cmd == CMD_POP)
+ {
+ SET(compiled_code, patstack[--patstacknext]);
+ }
+ else
+ {
+ PCRE2_CODE_COPY_FROM_VOID(compiled_code, patstack[patstacknext - 1]);
+ }
+
+ if (pat_patctl.jit != 0)
+ {
+ PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+ }
+ if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
+ if ((pat_patctl.control & CTL_FRAMESIZE) != 0) show_framesize();
+ if ((pat_patctl.control & CTL_ANYINFO) != 0)
+ {
+ rc = show_pattern_info();
+ if (rc != PR_OK) return rc;
+ }
+ break;
+
+ /* Save the stack of compiled patterns to a file, then empty the stack. */
+
+ case CMD_SAVE:
+ if (patstacknext <= 0)
+ {
+ fprintf(outfile, "** No stacked patterns to save\n");
+ return PR_OK;
+ }
+
+ rc = open_file(argptr+1, BINARY_OUTPUT_MODE, &f);
+ if (rc != PR_OK) return rc;
+
+ PCRE2_SERIALIZE_ENCODE(rc, patstack, patstacknext, &serial, &serial_size,
+ general_context);
+ if (rc < 0)
+ {
+ fclose(f);
+ if (!serial_error(rc, "Serialization")) return PR_ABEND;
+ break;
+ }
+
+ /* Write the length at the start of the file to make it straightforward to
+ get the right memory when re-loading. This saves having to read the file size
+ in different operating systems. To allow for different endianness (even
+ though reloading with the opposite endianness does not work), write the
+ length byte-by-byte. */
+
+ for (i = 0; i < 4; i++) fputc((serial_size >> (i*8)) & 255, f);
+ if (fwrite(serial, 1, serial_size, f) != serial_size)
+ {
+ fprintf(outfile, "** Wrong return from fwrite()\n");
+ fclose(f);
+ return PR_ABEND;
+ }
+
+ fclose(f);
+ PCRE2_SERIALIZE_FREE(serial);
+ while(patstacknext > 0)
+ {
+ SET(compiled_code, patstack[--patstacknext]);
+ SUB1(pcre2_code_free, compiled_code);
+ }
+ SET(compiled_code, NULL);
+ break;
+
+ /* Load a set of compiled patterns from a file onto the stack */
+
+ case CMD_LOAD:
+ rc = open_file(argptr+1, BINARY_INPUT_MODE, &f);
+ if (rc != PR_OK) return rc;
+
+ serial_size = 0;
+ for (i = 0; i < 4; i++) serial_size |= fgetc(f) << (i*8);
+
+ serial = malloc(serial_size);
+ if (serial == NULL)
+ {
+ fprintf(outfile, "** Failed to get memory (size %" SIZ_FORM ") for #load\n",
+ SIZ_CAST serial_size);
+ fclose(f);
+ return PR_ABEND;
+ }
+
+ i = fread(serial, 1, serial_size, f);
+ fclose(f);
+
+ if (i != serial_size)
+ {
+ fprintf(outfile, "** Wrong return from fread()\n");
+ yield = PR_ABEND;
+ }
+ else
+ {
+ PCRE2_SERIALIZE_GET_NUMBER_OF_CODES(rc, serial);
+ if (rc < 0)
+ {
+ if (!serial_error(rc, "Get number of codes")) yield = PR_ABEND;
+ }
+ else
+ {
+ if (rc + patstacknext > PATSTACKSIZE)
+ {
+ fprintf(outfile, "** Not enough space on pattern stack for %d pattern%s\n",
+ rc, (rc == 1)? "" : "s");
+ rc = PATSTACKSIZE - patstacknext;
+ fprintf(outfile, "** Decoding %d pattern%s\n", rc,
+ (rc == 1)? "" : "s");
+ }
+ PCRE2_SERIALIZE_DECODE(rc, patstack + patstacknext, rc, serial,
+ general_context);
+ if (rc < 0)
+ {
+ if (!serial_error(rc, "Deserialization")) yield = PR_ABEND;
+ }
+ else patstacknext += rc;
+ }
+ }
+
+ free(serial);
+ break;
+ }
+
+return yield;
+}
+
+
+
+/*************************************************
+* Process pattern line *
+*************************************************/
+
+/* This function is called when the input buffer contains the start of a
+pattern. The first character is known to be a valid delimiter. The pattern is
+read, modifiers are interpreted, and a suitable local context is set up for
+this test. The pattern is then compiled.
+
+Arguments: none
+
+Returns: PR_OK continue processing next line
+ PR_SKIP skip to a blank line
+ PR_ABEND abort the pcre2test run
+*/
+
+static int
+process_pattern(void)
+{
+BOOL utf;
+uint32_t k;
+uint8_t *p = buffer;
+unsigned int delimiter = *p++;
+int errorcode;
+void *use_pat_context;
+uint32_t use_forbid_utf = forbid_utf;
+PCRE2_SIZE patlen;
+PCRE2_SIZE valgrind_access_length;
+PCRE2_SIZE erroroffset;
+
+/* Initialize the context and pattern/data controls for this test from the
+defaults. */
+
+PATCTXCPY(pat_context, default_pat_context);
+memcpy(&pat_patctl, &def_patctl, sizeof(patctl));
+
+/* Find the end of the pattern, reading more lines if necessary. */
+
+for(;;)
+ {
+ while (*p != 0)
+ {
+ if (*p == '\\' && p[1] != 0) p++;
+ else if (*p == delimiter) break;
+ p++;
+ }
+ if (*p != 0) break;
+ if ((p = extend_inputline(infile, p, " > ")) == NULL)
+ {
+ fprintf(outfile, "** Unexpected EOF\n");
+ return PR_ABEND;
+ }
+ if (!INTERACTIVE(infile)) fprintf(outfile, "%s", (char *)p);
+ }
+
+/* If the first character after the delimiter is backslash, make the pattern
+end with backslash. This is purely to provide a way of testing for the error
+message when a pattern ends with backslash. */
+
+if (p[1] == '\\') *p++ = '\\';
+
+/* Terminate the pattern at the delimiter, and compute the length. */
+
+*p++ = 0;
+patlen = p - buffer - 2;
+
+/* Look for modifiers and options after the final delimiter. */
+
+if (!decode_modifiers(p, CTX_PAT, &pat_patctl, NULL)) return PR_SKIP;
+utf = (pat_patctl.options & PCRE2_UTF) != 0;
+
+/* The utf8_input modifier is not allowed in 8-bit mode, and is mutually
+exclusive with the utf modifier. */
+
+if ((pat_patctl.control & CTL_UTF8_INPUT) != 0)
+ {
+ if (test_mode == PCRE8_MODE)
+ {
+ fprintf(outfile, "** The utf8_input modifier is not allowed in 8-bit mode\n");
+ return PR_SKIP;
+ }
+ if (utf)
+ {
+ fprintf(outfile, "** The utf and utf8_input modifiers are mutually exclusive\n");
+ return PR_SKIP;
+ }
+ }
+
+/* The convert and posix modifiers are mutually exclusive. */
+
+if (pat_patctl.convert_type != CONVERT_UNSET &&
+ (pat_patctl.control & CTL_POSIX) != 0)
+ {
+ fprintf(outfile, "** The convert and posix modifiers are mutually exclusive\n");
+ return PR_SKIP;
+ }
+
+/* Check for mutually exclusive control modifiers. At present, these are all in
+the first control word. */
+
+for (k = 0; k < sizeof(exclusive_pat_controls)/sizeof(uint32_t); k++)
+ {
+ uint32_t c = pat_patctl.control & exclusive_pat_controls[k];
+ if (c != 0 && c != (c & (~c+1)))
+ {
+ show_controls(c, 0, "** Not allowed together:");
+ fprintf(outfile, "\n");
+ return PR_SKIP;
+ }
+ }
+
+/* Assume full JIT compile for jitverify and/or jitfast if nothing else was
+specified. */
+
+if (pat_patctl.jit == 0 &&
+ (pat_patctl.control & (CTL_JITVERIFY|CTL_JITFAST)) != 0)
+ pat_patctl.jit = 7;
+
+/* Now copy the pattern to pbuffer8 for use in 8-bit testing and for reflecting
+in callouts. Convert from hex if requested (literal strings in quotes may be
+present within the hexadecimal pairs). The result must necessarily be fewer
+characters so will always fit in pbuffer8. */
+
+if ((pat_patctl.control & CTL_HEXPAT) != 0)
+ {
+ uint8_t *pp, *pt;
+ uint32_t c, d;
+
+ pt = pbuffer8;
+ for (pp = buffer + 1; *pp != 0; pp++)
+ {
+ if (isspace(*pp)) continue;
+ c = *pp++;
+
+ /* Handle a literal substring */
+
+ if (c == '\'' || c == '"')
+ {
+ uint8_t *pq = pp;
+ for (;; pp++)
+ {
+ d = *pp;
+ if (d == 0)
+ {
+ fprintf(outfile, "** Missing closing quote in hex pattern: "
+ "opening quote is at offset %" PTR_FORM ".\n", pq - buffer - 2);
+ return PR_SKIP;
+ }
+ if (d == c) break;
+ *pt++ = d;
+ }
+ }
+
+ /* Expect a hex pair */
+
+ else
+ {
+ if (!isxdigit(c))
+ {
+ fprintf(outfile, "** Unexpected non-hex-digit '%c' at offset %"
+ PTR_FORM " in hex pattern: quote missing?\n", c, pp - buffer - 2);
+ return PR_SKIP;
+ }
+ if (*pp == 0)
+ {
+ fprintf(outfile, "** Odd number of digits in hex pattern\n");
+ return PR_SKIP;
+ }
+ d = *pp;
+ if (!isxdigit(d))
+ {
+ fprintf(outfile, "** Unexpected non-hex-digit '%c' at offset %"
+ PTR_FORM " in hex pattern: quote missing?\n", d, pp - buffer - 1);
+ return PR_SKIP;
+ }
+ c = toupper(c);
+ d = toupper(d);
+ *pt++ = ((isdigit(c)? (c - '0') : (c - 'A' + 10)) << 4) +
+ (isdigit(d)? (d - '0') : (d - 'A' + 10));
+ }
+ }
+ *pt = 0;
+ patlen = pt - pbuffer8;
+ }
+
+/* If not a hex string, process for repetition expansion if requested. */
+
+else if ((pat_patctl.control & CTL_EXPAND) != 0)
+ {
+ uint8_t *pp, *pt;
+
+ pt = pbuffer8;
+ for (pp = buffer + 1; *pp != 0; pp++)
+ {
+ uint8_t *pc = pp;
+ uint32_t count = 1;
+ size_t length = 1;
+
+ /* Check for replication syntax; if not found, the defaults just set will
+ prevail and one character will be copied. */
+
+ if (pp[0] == '\\' && pp[1] == '[')
+ {
+ uint8_t *pe;
+ for (pe = pp + 2; *pe != 0; pe++)
+ {
+ if (pe[0] == ']' && pe[1] == '{')
+ {
+ uint32_t clen = pe - pc - 2;
+ uint32_t i = 0;
+ unsigned long uli;
+ char *endptr;
+
+ pe += 2;
+ uli = strtoul((const char *)pe, &endptr, 10);
+ if (U32OVERFLOW(uli))
+ {
+ fprintf(outfile, "** Pattern repeat count too large\n");
+ return PR_SKIP;
+ }
+
+ i = (uint32_t)uli;
+ pe = (uint8_t *)endptr;
+ if (*pe == '}')
+ {
+ if (i == 0)
+ {
+ fprintf(outfile, "** Zero repeat not allowed\n");
+ return PR_SKIP;
+ }
+ pc += 2;
+ count = i;
+ length = clen;
+ pp = pe;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Add to output. If the buffer is too small expand it. The function for
+ expanding buffers always keeps buffer and pbuffer8 in step as far as their
+ size goes. */
+
+ while (pt + count * length > pbuffer8 + pbuffer8_size)
+ {
+ size_t pc_offset = pc - buffer;
+ size_t pp_offset = pp - buffer;
+ size_t pt_offset = pt - pbuffer8;
+ expand_input_buffers();
+ pc = buffer + pc_offset;
+ pp = buffer + pp_offset;
+ pt = pbuffer8 + pt_offset;
+ }
+
+ for (; count > 0; count--)
+ {
+ memcpy(pt, pc, length);
+ pt += length;
+ }
+ }
+
+ *pt = 0;
+ patlen = pt - pbuffer8;
+
+ if ((pat_patctl.control & CTL_INFO) != 0)
+ fprintf(outfile, "Expanded: %s\n", pbuffer8);
+ }
+
+/* Neither hex nor expanded, just copy the input verbatim. */
+
+else
+ {
+ strncpy((char *)pbuffer8, (char *)(buffer+1), patlen + 1);
+ }
+
+/* Sort out character tables */
+
+if (pat_patctl.locale[0] != 0)
+ {
+ if (pat_patctl.tables_id != 0)
+ {
+ fprintf(outfile, "** 'Locale' and 'tables' must not both be set\n");
+ return PR_SKIP;
+ }
+ if (setlocale(LC_CTYPE, (const char *)pat_patctl.locale) == NULL)
+ {
+ fprintf(outfile, "** Failed to set locale '%s'\n", pat_patctl.locale);
+ return PR_SKIP;
+ }
+ if (strcmp((const char *)pat_patctl.locale, (const char *)locale_name) != 0)
+ {
+ strcpy((char *)locale_name, (char *)pat_patctl.locale);
+ if (locale_tables != NULL) free((void *)locale_tables);
+ PCRE2_MAKETABLES(locale_tables);
+ }
+ use_tables = locale_tables;
+ }
+
+else switch (pat_patctl.tables_id)
+ {
+ case 0: use_tables = NULL; break;
+ case 1: use_tables = tables1; break;
+ case 2: use_tables = tables2; break;
+ default:
+ fprintf(outfile, "** 'Tables' must specify 0, 1, or 2.\n");
+ return PR_SKIP;
+ }
+
+PCRE2_SET_CHARACTER_TABLES(pat_context, use_tables);
+
+/* Set up for the stackguard test. */
+
+if (pat_patctl.stackguard_test != 0)
+ {
+ PCRE2_SET_COMPILE_RECURSION_GUARD(pat_context, stack_guard, NULL);
+ }
+
+/* Handle compiling via the POSIX interface, which doesn't support the
+timing, showing, or debugging options, nor the ability to pass over
+local character tables. Neither does it have 16-bit or 32-bit support. */
+
+if ((pat_patctl.control & CTL_POSIX) != 0)
+ {
+#ifdef SUPPORT_PCRE2_8
+ int rc;
+ int cflags = 0;
+ const char *msg = "** Ignored with POSIX interface:";
+#endif
+
+ if (test_mode != PCRE8_MODE)
+ {
+ fprintf(outfile, "** The POSIX interface is available only in 8-bit mode\n");
+ return PR_SKIP;
+ }
+
+#ifdef SUPPORT_PCRE2_8
+ /* Check for features that the POSIX interface does not support. */
+
+ if (pat_patctl.locale[0] != 0) prmsg(&msg, "locale");
+ if (pat_patctl.replacement[0] != 0) prmsg(&msg, "replace");
+ if (pat_patctl.tables_id != 0) prmsg(&msg, "tables");
+ if (pat_patctl.stackguard_test != 0) prmsg(&msg, "stackguard");
+ if (timeit > 0) prmsg(&msg, "timing");
+ if (pat_patctl.jit != 0) prmsg(&msg, "JIT");
+
+ if ((pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS) != 0)
+ {
+ show_compile_options(
+ pat_patctl.options & ~POSIX_SUPPORTED_COMPILE_OPTIONS, msg, "");
+ msg = "";
+ }
+
+ if ((FLD(pat_context, extra_options) &
+ ~POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS) != 0)
+ {
+ show_compile_extra_options(
+ FLD(pat_context, extra_options) & ~POSIX_SUPPORTED_COMPILE_EXTRA_OPTIONS,
+ msg, "");
+ msg = "";
+ }
+
+ if ((pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS) != 0 ||
+ (pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2) != 0)
+ {
+ show_controls(pat_patctl.control & ~POSIX_SUPPORTED_COMPILE_CONTROLS,
+ pat_patctl.control2 & ~POSIX_SUPPORTED_COMPILE_CONTROLS2, msg);
+ msg = "";
+ }
+
+ if (local_newline_default != 0) prmsg(&msg, "#newline_default");
+ if (FLD(pat_context, max_pattern_length) != PCRE2_UNSET)
+ prmsg(&msg, "max_pattern_length");
+ if (FLD(pat_context, parens_nest_limit) != PARENS_NEST_DEFAULT)
+ prmsg(&msg, "parens_nest_limit");
+
+ if (msg[0] == 0) fprintf(outfile, "\n");
+
+ /* Translate PCRE2 options to POSIX options and then compile. */
+
+ if (utf) cflags |= REG_UTF;
+ if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0) cflags |= REG_NOSUB;
+ if ((pat_patctl.options & PCRE2_UCP) != 0) cflags |= REG_UCP;
+ if ((pat_patctl.options & PCRE2_CASELESS) != 0) cflags |= REG_ICASE;
+ if ((pat_patctl.options & PCRE2_LITERAL) != 0) cflags |= REG_NOSPEC;
+ if ((pat_patctl.options & PCRE2_MULTILINE) != 0) cflags |= REG_NEWLINE;
+ if ((pat_patctl.options & PCRE2_DOTALL) != 0) cflags |= REG_DOTALL;
+ if ((pat_patctl.options & PCRE2_UNGREEDY) != 0) cflags |= REG_UNGREEDY;
+
+ if ((pat_patctl.control & (CTL_HEXPAT|CTL_USE_LENGTH)) != 0)
+ {
+ preg.re_endp = (char *)pbuffer8 + patlen;
+ cflags |= REG_PEND;
+ }
+
+ rc = regcomp(&preg, (char *)pbuffer8, cflags);
+
+ /* Compiling failed */
+
+ if (rc != 0)
+ {
+ size_t bsize, usize;
+ int psize;
+
+ preg.re_pcre2_code = NULL; /* In case something was left in there */
+ preg.re_match_data = NULL;
+
+ bsize = (pat_patctl.regerror_buffsize != 0)?
+ pat_patctl.regerror_buffsize : pbuffer8_size;
+ if (bsize + 8 < pbuffer8_size)
+ memcpy(pbuffer8 + bsize, "DEADBEEF", 8);
+ usize = regerror(rc, &preg, (char *)pbuffer8, bsize);
+
+ /* Inside regerror(), snprintf() is used. If the buffer is too small, some
+ versions of snprintf() put a zero byte at the end, but others do not.
+ Therefore, we print a maximum of one less than the size of the buffer. */
+
+ psize = (int)bsize - 1;
+ fprintf(outfile, "Failed: POSIX code %d: %.*s\n", rc, psize, pbuffer8);
+ if (usize > bsize)
+ {
+ fprintf(outfile, "** regerror() message truncated\n");
+ if (memcmp(pbuffer8 + bsize, "DEADBEEF", 8) != 0)
+ fprintf(outfile, "** regerror() buffer overflow\n");
+ }
+ return PR_SKIP;
+ }
+
+ /* Compiling succeeded. Check that the values in the preg block are sensible.
+ It can happen that pcre2test is accidentally linked with a different POSIX
+ library which succeeds, but of course puts different things into preg. In
+ this situation, calling regfree() may cause a segfault (or invalid free() in
+ valgrind), so ensure that preg.re_pcre2_code is NULL, which suppresses the
+ calling of regfree() on exit. */
+
+ if (preg.re_pcre2_code == NULL ||
+ ((pcre2_real_code_8 *)preg.re_pcre2_code)->magic_number != MAGIC_NUMBER ||
+ ((pcre2_real_code_8 *)preg.re_pcre2_code)->top_bracket != preg.re_nsub ||
+ preg.re_match_data == NULL ||
+ preg.re_cflags != cflags)
+ {
+ fprintf(outfile,
+ "** The regcomp() function returned zero (success), but the values set\n"
+ "** in the preg block are not valid for PCRE2. Check that pcre2test is\n"
+ "** linked with PCRE2's pcre2posix module (-lpcre2-posix) and not with\n"
+ "** some other POSIX regex library.\n**\n");
+ preg.re_pcre2_code = NULL;
+ return PR_ABEND;
+ }
+
+ return PR_OK;
+#endif /* SUPPORT_PCRE2_8 */
+ }
+
+/* Handle compiling via the native interface. Controls that act later are
+ignored with "push". Replacements are locked out. */
+
+if ((pat_patctl.control & (CTL_PUSH|CTL_PUSHCOPY|CTL_PUSHTABLESCOPY)) != 0)
+ {
+ if (pat_patctl.replacement[0] != 0)
+ {
+ fprintf(outfile, "** Replacement text is not supported with 'push'.\n");
+ return PR_OK;
+ }
+ if ((pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS) != 0 ||
+ (pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2) != 0)
+ {
+ show_controls(pat_patctl.control & ~PUSH_SUPPORTED_COMPILE_CONTROLS,
+ pat_patctl.control2 & ~PUSH_SUPPORTED_COMPILE_CONTROLS2,
+ "** Ignored when compiled pattern is stacked with 'push':");
+ fprintf(outfile, "\n");
+ }
+ if ((pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS) != 0 ||
+ (pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2) != 0)
+ {
+ show_controls(pat_patctl.control & PUSH_COMPILE_ONLY_CONTROLS,
+ pat_patctl.control2 & PUSH_COMPILE_ONLY_CONTROLS2,
+ "** Applies only to compile when pattern is stacked with 'push':");
+ fprintf(outfile, "\n");
+ }
+ }
+
+/* Convert the input in non-8-bit modes. */
+
+errorcode = 0;
+
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE) errorcode = to16(pbuffer8, utf, &patlen);
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE) errorcode = to32(pbuffer8, utf, &patlen);
+#endif
+
+switch(errorcode)
+ {
+ case -1:
+ fprintf(outfile, "** Failed: invalid UTF-8 string cannot be "
+ "converted to %d-bit string\n", (test_mode == PCRE16_MODE)? 16:32);
+ return PR_SKIP;
+
+ case -2:
+ fprintf(outfile, "** Failed: character value greater than 0x10ffff "
+ "cannot be converted to UTF\n");
+ return PR_SKIP;
+
+ case -3:
+ fprintf(outfile, "** Failed: character value greater than 0xffff "
+ "cannot be converted to 16-bit in non-UTF mode\n");
+ return PR_SKIP;
+
+ default:
+ break;
+ }
+
+/* The pattern is now in pbuffer[8|16|32], with the length in code units in
+patlen. If it is to be converted, copy the result back afterwards so that it
+ends up back in the usual place. */
+
+if (pat_patctl.convert_type != CONVERT_UNSET)
+ {
+ int rc;
+ int convert_return = PR_OK;
+ uint32_t convert_options = pat_patctl.convert_type;
+ void *converted_pattern;
+ PCRE2_SIZE converted_length;
+
+ if (pat_patctl.convert_length != 0)
+ {
+ converted_length = pat_patctl.convert_length;
+ converted_pattern = malloc(converted_length * code_unit_size);
+ if (converted_pattern == NULL)
+ {
+ fprintf(outfile, "** Failed: malloc failed for converted pattern\n");
+ return PR_SKIP;
+ }
+ }
+ else converted_pattern = NULL; /* Let the library allocate */
+
+ if (utf) convert_options |= PCRE2_CONVERT_UTF;
+ if ((pat_patctl.options & PCRE2_NO_UTF_CHECK) != 0)
+ convert_options |= PCRE2_CONVERT_NO_UTF_CHECK;
+
+ CONCTXCPY(con_context, default_con_context);
+
+ if (pat_patctl.convert_glob_escape != 0)
+ {
+ uint32_t escape = (pat_patctl.convert_glob_escape == '0')? 0 :
+ pat_patctl.convert_glob_escape;
+ PCRE2_SET_GLOB_ESCAPE(rc, con_context, escape);
+ if (rc != 0)
+ {
+ fprintf(outfile, "** Invalid glob escape '%c'\n",
+ pat_patctl.convert_glob_escape);
+ convert_return = PR_SKIP;
+ goto CONVERT_FINISH;
+ }
+ }
+
+ if (pat_patctl.convert_glob_separator != 0)
+ {
+ PCRE2_SET_GLOB_SEPARATOR(rc, con_context, pat_patctl.convert_glob_separator);
+ if (rc != 0)
+ {
+ fprintf(outfile, "** Invalid glob separator '%c'\n",
+ pat_patctl.convert_glob_separator);
+ convert_return = PR_SKIP;
+ goto CONVERT_FINISH;
+ }
+ }
+
+ PCRE2_PATTERN_CONVERT(rc, pbuffer, patlen, convert_options,
+ &converted_pattern, &converted_length, con_context);
+
+ if (rc != 0)
+ {
+ fprintf(outfile, "** Pattern conversion error at offset %" SIZ_FORM ": ",
+ SIZ_CAST converted_length);
+ convert_return = print_error_message(rc, "", "\n")? PR_SKIP:PR_ABEND;
+ }
+
+ /* Output the converted pattern, then copy it. */
+
+ else
+ {
+ PCHARSV(converted_pattern, 0, converted_length, utf, outfile);
+ fprintf(outfile, "\n");
+ patlen = converted_length;
+ CONVERT_COPY(pbuffer, converted_pattern, converted_length + 1);
+ }
+
+ /* Free the converted pattern. */
+
+ CONVERT_FINISH:
+ if (pat_patctl.convert_length != 0)
+ free(converted_pattern);
+ else
+ PCRE2_CONVERTED_PATTERN_FREE(converted_pattern);
+
+ /* Return if conversion was unsuccessful. */
+
+ if (convert_return != PR_OK) return convert_return;
+ }
+
+/* By default we pass a zero-terminated pattern, but a length is passed if
+"use_length" was specified or this is a hex pattern (which might contain binary
+zeros). When valgrind is supported, arrange for the unused part of the buffer
+to be marked as no access. */
+
+valgrind_access_length = patlen;
+if ((pat_patctl.control & (CTL_HEXPAT|CTL_USE_LENGTH)) == 0)
+ {
+ patlen = PCRE2_ZERO_TERMINATED;
+ valgrind_access_length += 1; /* For the terminating zero */
+ }
+
+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE && pbuffer8 != NULL)
+ {
+ VALGRIND_MAKE_MEM_NOACCESS(pbuffer8 + valgrind_access_length,
+ pbuffer8_size - valgrind_access_length);
+ }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE && pbuffer16 != NULL)
+ {
+ VALGRIND_MAKE_MEM_NOACCESS(pbuffer16 + valgrind_access_length,
+ pbuffer16_size - valgrind_access_length*sizeof(uint16_t));
+ }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE && pbuffer32 != NULL)
+ {
+ VALGRIND_MAKE_MEM_NOACCESS(pbuffer32 + valgrind_access_length,
+ pbuffer32_size - valgrind_access_length*sizeof(uint32_t));
+ }
+#endif
+#else /* Valgrind not supported */
+(void)valgrind_access_length; /* Avoid compiler warning */
+#endif
+
+/* If #newline_default has been used and the library was not compiled with an
+appropriate default newline setting, local_newline_default will be non-zero. We
+use this if there is no explicit newline modifier. */
+
+if ((pat_patctl.control2 & CTL2_NL_SET) == 0 && local_newline_default != 0)
+ {
+ SETFLD(pat_context, newline_convention, local_newline_default);
+ }
+
+/* The null_context modifier is used to test calling pcre2_compile() with a
+NULL context. */
+
+use_pat_context = ((pat_patctl.control & CTL_NULLCONTEXT) != 0)?
+ NULL : PTR(pat_context);
+
+/* If PCRE2_LITERAL is set, set use_forbid_utf zero because PCRE2_NEVER_UTF
+and PCRE2_NEVER_UCP are invalid with it. */
+
+if ((pat_patctl.options & PCRE2_LITERAL) != 0) use_forbid_utf = 0;
+
+/* Compile many times when timing. */
+
+if (timeit > 0)
+ {
+ int i;
+ clock_t time_taken = 0;
+ for (i = 0; i < timeit; i++)
+ {
+ clock_t start_time = clock();
+ PCRE2_COMPILE(compiled_code, pbuffer, patlen,
+ pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset,
+ use_pat_context);
+ time_taken += clock() - start_time;
+ if (TEST(compiled_code, !=, NULL))
+ { SUB1(pcre2_code_free, compiled_code); }
+ }
+ total_compile_time += time_taken;
+ fprintf(outfile, "Compile time %.4f milliseconds\n",
+ (((double)time_taken * 1000.0) / (double)timeit) /
+ (double)CLOCKS_PER_SEC);
+ }
+
+/* A final compile that is used "for real". */
+
+PCRE2_COMPILE(compiled_code, pbuffer, patlen, pat_patctl.options|use_forbid_utf,
+ &errorcode, &erroroffset, use_pat_context);
+
+/* Call the JIT compiler if requested. When timing, we must free and recompile
+the pattern each time because that is the only way to free the JIT compiled
+code. We know that compilation will always succeed. */
+
+if (TEST(compiled_code, !=, NULL) && pat_patctl.jit != 0)
+ {
+ if (timeit > 0)
+ {
+ int i;
+ clock_t time_taken = 0;
+ for (i = 0; i < timeit; i++)
+ {
+ clock_t start_time;
+ SUB1(pcre2_code_free, compiled_code);
+ PCRE2_COMPILE(compiled_code, pbuffer, patlen,
+ pat_patctl.options|use_forbid_utf, &errorcode, &erroroffset,
+ use_pat_context);
+ start_time = clock();
+ PCRE2_JIT_COMPILE(jitrc,compiled_code, pat_patctl.jit);
+ time_taken += clock() - start_time;
+ }
+ total_jit_compile_time += time_taken;
+ fprintf(outfile, "JIT compile %.4f milliseconds\n",
+ (((double)time_taken * 1000.0) / (double)timeit) /
+ (double)CLOCKS_PER_SEC);
+ }
+ else
+ {
+ PCRE2_JIT_COMPILE(jitrc, compiled_code, pat_patctl.jit);
+ }
+ }
+
+/* If valgrind is supported, mark the pbuffer as accessible again. The 16-bit
+and 32-bit buffers can be marked completely undefined, but we must leave the
+pattern in the 8-bit buffer defined because it may be read from a callout
+during matching. */
+
+#ifdef SUPPORT_VALGRIND
+#ifdef SUPPORT_PCRE2_8
+if (test_mode == PCRE8_MODE)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(pbuffer8 + valgrind_access_length,
+ pbuffer8_size - valgrind_access_length);
+ }
+#endif
+#ifdef SUPPORT_PCRE2_16
+if (test_mode == PCRE16_MODE)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(pbuffer16, pbuffer16_size);
+ }
+#endif
+#ifdef SUPPORT_PCRE2_32
+if (test_mode == PCRE32_MODE)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(pbuffer32, pbuffer32_size);
+ }
+#endif
+#endif
+
+/* Compilation failed; go back for another re, skipping to blank line
+if non-interactive. */
+
+if (TEST(compiled_code, ==, NULL))
+ {
+ fprintf(outfile, "Failed: error %d at offset %d: ", errorcode,
+ (int)erroroffset);
+ if (!print_error_message(errorcode, "", "\n")) return PR_ABEND;
+ return PR_SKIP;
+ }
+
+/* If forbid_utf is non-zero, we are running a non-UTF test. UTF and UCP are
+locked out at compile time, but we must also check for occurrences of \P, \p,
+and \X, which are only supported when Unicode is supported. */
+
+if (forbid_utf != 0)
+ {
+ if ((FLD(compiled_code, flags) & PCRE2_HASBKPORX) != 0)
+ {
+ fprintf(outfile, "** \\P, \\p, and \\X are not allowed after the "
+ "#forbid_utf command\n");
+ return PR_SKIP;
+ }
+ }
+
+/* Remember the maximum lookbehind, for partial matching. */
+
+if (pattern_info(PCRE2_INFO_MAXLOOKBEHIND, &maxlookbehind, FALSE) != 0)
+ return PR_ABEND;
+
+/* If an explicit newline modifier was given, set the information flag in the
+pattern so that it is preserved over push/pop. */
+
+if ((pat_patctl.control2 & CTL2_NL_SET) != 0)
+ {
+ SETFLD(compiled_code, flags, FLD(compiled_code, flags) | PCRE2_NL_SET);
+ }
+
+/* Output code size and other information if requested. */
+
+if ((pat_patctl.control & CTL_MEMORY) != 0) show_memory_info();
+if ((pat_patctl.control & CTL_FRAMESIZE) != 0) show_framesize();
+if ((pat_patctl.control & CTL_ANYINFO) != 0)
+ {
+ int rc = show_pattern_info();
+ if (rc != PR_OK) return rc;
+ }
+
+/* The "push" control requests that the compiled pattern be remembered on a
+stack. This is mainly for testing the serialization functionality. */
+
+if ((pat_patctl.control & CTL_PUSH) != 0)
+ {
+ if (patstacknext >= PATSTACKSIZE)
+ {
+ fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE);
+ return PR_ABEND;
+ }
+ patstack[patstacknext++] = PTR(compiled_code);
+ SET(compiled_code, NULL);
+ }
+
+/* The "pushcopy" and "pushtablescopy" controls are similar, but push a
+copy of the pattern, the latter with a copy of its character tables. This tests
+the pcre2_code_copy() and pcre2_code_copy_with_tables() functions. */
+
+if ((pat_patctl.control & (CTL_PUSHCOPY|CTL_PUSHTABLESCOPY)) != 0)
+ {
+ if (patstacknext >= PATSTACKSIZE)
+ {
+ fprintf(outfile, "** Too many pushed patterns (max %d)\n", PATSTACKSIZE);
+ return PR_ABEND;
+ }
+ if ((pat_patctl.control & CTL_PUSHCOPY) != 0)
+ {
+ PCRE2_CODE_COPY_TO_VOID(patstack[patstacknext++], compiled_code);
+ }
+ else
+ {
+ PCRE2_CODE_COPY_WITH_TABLES_TO_VOID(patstack[patstacknext++],
+ compiled_code); }
+ }
+
+return PR_OK;
+}
+
+
+
+/*************************************************
+* Check heap, match or depth limit *
+*************************************************/
+
+/* This is used for DFA, normal, and JIT fast matching. For DFA matching it
+should only be called with the third argument set to PCRE2_ERROR_DEPTHLIMIT.
+
+Arguments:
+ pp the subject string
+ ulen length of subject or PCRE2_ZERO_TERMINATED
+ errnumber defines which limit to test
+ msg string to include in final message
+
+Returns: the return from the final match function call
+*/
+
+static int
+check_match_limit(uint8_t *pp, PCRE2_SIZE ulen, int errnumber, const char *msg)
+{
+int capcount;
+uint32_t min = 0;
+uint32_t mid = 64;
+uint32_t max = UINT32_MAX;
+
+PCRE2_SET_MATCH_LIMIT(dat_context, max);
+PCRE2_SET_DEPTH_LIMIT(dat_context, max);
+PCRE2_SET_HEAP_LIMIT(dat_context, max);
+
+for (;;)
+ {
+ uint32_t stack_start = 0;
+
+ if (errnumber == PCRE2_ERROR_HEAPLIMIT)
+ {
+ PCRE2_SET_HEAP_LIMIT(dat_context, mid);
+ }
+ else if (errnumber == PCRE2_ERROR_MATCHLIMIT)
+ {
+ PCRE2_SET_MATCH_LIMIT(dat_context, mid);
+ }
+ else
+ {
+ PCRE2_SET_DEPTH_LIMIT(dat_context, mid);
+ }
+
+ if ((dat_datctl.control & CTL_DFA) != 0)
+ {
+ stack_start = DFA_START_RWS_SIZE/1024;
+ if (dfa_workspace == NULL)
+ dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int));
+ if (dfa_matched++ == 0)
+ dfa_workspace[0] = -1; /* To catch bad restart */
+ PCRE2_DFA_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset,
+ dat_datctl.options, match_data,
+ PTR(dat_context), dfa_workspace, DFA_WS_DIMENSION);
+ }
+
+ else if ((pat_patctl.control & CTL_JITFAST) != 0)
+ PCRE2_JIT_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset,
+ dat_datctl.options, match_data, PTR(dat_context));
+
+ else
+ {
+ stack_start = START_FRAMES_SIZE/1024;
+ PCRE2_MATCH(capcount, compiled_code, pp, ulen, dat_datctl.offset,
+ dat_datctl.options, match_data, PTR(dat_context));
+ }
+
+ if (capcount == errnumber)
+ {
+ if ((mid & 0x80000000u) != 0)
+ {
+ fprintf(outfile, "Can't find minimum %s limit: check pattern for "
+ "restriction\n", msg);
+ break;
+ }
+
+ min = mid;
+ mid = (mid == max - 1)? max : (max != UINT32_MAX)? (min + max)/2 : mid*2;
+ }
+ else if (capcount >= 0 ||
+ capcount == PCRE2_ERROR_NOMATCH ||
+ capcount == PCRE2_ERROR_PARTIAL)
+ {
+ /* If we've not hit the error with a heap limit less than the size of the
+ initial stack frame vector (for pcre2_match()) or the initial stack
+ workspace vector (for pcre2_dfa_match()), the heap is not being used, so
+ the minimum limit is zero; there's no need to go on. The other limits are
+ always greater than zero. */
+
+ if (errnumber == PCRE2_ERROR_HEAPLIMIT && mid < stack_start)
+ {
+ fprintf(outfile, "Minimum %s limit = 0\n", msg);
+ break;
+ }
+ if (mid == min + 1)
+ {
+ fprintf(outfile, "Minimum %s limit = %d\n", msg, mid);
+ break;
+ }
+ max = mid;
+ mid = (min + max)/2;
+ }
+ else break; /* Some other error */
+ }
+
+return capcount;
+}
+
+
+
+/*************************************************
+* Callout function *
+*************************************************/
+
+/* Called from a PCRE2 library as a result of the (?C) item. We print out where
+we are in the match (unless suppressed). Yield zero unless more callouts than
+the fail count, or the callout data is not zero. The only differences in the
+callout block for different code unit widths are that the pointers to the
+subject, the most recent MARK, and a callout argument string point to strings
+of the appropriate width. Casts can be used to deal with this.
+
+Argument: a pointer to a callout block
+Return:
+*/
+
+static int
+callout_function(pcre2_callout_block_8 *cb, void *callout_data_ptr)
+{
+FILE *f, *fdefault;
+uint32_t i, pre_start, post_start, subject_length;
+PCRE2_SIZE current_position;
+BOOL utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+BOOL callout_capture = (dat_datctl.control & CTL_CALLOUT_CAPTURE) != 0;
+BOOL callout_where = (dat_datctl.control2 & CTL2_CALLOUT_NO_WHERE) == 0;
+
+/* The FILE f is used for echoing the subject string if it is non-NULL. This
+happens only once in simple cases, but we want to repeat after any additional
+output caused by CALLOUT_EXTRA. */
+
+fdefault = (!first_callout && !callout_capture && cb->callout_string == NULL)?
+ NULL : outfile;
+
+if ((dat_datctl.control2 & CTL2_CALLOUT_EXTRA) != 0)
+ {
+ f = outfile;
+ switch (cb->callout_flags)
+ {
+ case PCRE2_CALLOUT_BACKTRACK:
+ fprintf(f, "Backtrack\n");
+ break;
+
+ case PCRE2_CALLOUT_STARTMATCH|PCRE2_CALLOUT_BACKTRACK:
+ fprintf(f, "Backtrack\nNo other matching paths\n");
+ /* Fall through */
+
+ case PCRE2_CALLOUT_STARTMATCH:
+ fprintf(f, "New match attempt\n");
+ break;
+
+ default:
+ f = fdefault;
+ break;
+ }
+ }
+else f = fdefault;
+
+/* For a callout with a string argument, show the string first because there
+isn't a tidy way to fit it in the rest of the data. */
+
+if (cb->callout_string != NULL)
+ {
+ uint32_t delimiter = CODE_UNIT(cb->callout_string, -1);
+ fprintf(outfile, "Callout (%" SIZ_FORM "): %c",
+ SIZ_CAST cb->callout_string_offset, delimiter);
+ PCHARSV(cb->callout_string, 0,
+ cb->callout_string_length, utf, outfile);
+ for (i = 0; callout_start_delims[i] != 0; i++)
+ if (delimiter == callout_start_delims[i])
+ {
+ delimiter = callout_end_delims[i];
+ break;
+ }
+ fprintf(outfile, "%c", delimiter);
+ if (!callout_capture) fprintf(outfile, "\n");
+ }
+
+/* Show captured strings if required */
+
+if (callout_capture)
+ {
+ if (cb->callout_string == NULL)
+ fprintf(outfile, "Callout %d:", cb->callout_number);
+ fprintf(outfile, " last capture = %d\n", cb->capture_last);
+ for (i = 2; i < cb->capture_top * 2; i += 2)
+ {
+ fprintf(outfile, "%2d: ", i/2);
+ if (cb->offset_vector[i] == PCRE2_UNSET)
+ fprintf(outfile, "<unset>");
+ else
+ {
+ PCHARSV(cb->subject, cb->offset_vector[i],
+ cb->offset_vector[i+1] - cb->offset_vector[i], utf, f);
+ }
+ fprintf(outfile, "\n");
+ }
+ }
+
+/* Unless suppressed, re-print the subject in canonical form (with escapes for
+non-printing characters), the first time, or if giving full details. On
+subsequent calls in the same match, we use PCHARS() just to find the printed
+lengths of the substrings. */
+
+if (callout_where)
+ {
+ if (f != NULL) fprintf(f, "--->");
+
+ /* The subject before the match start. */
+
+ PCHARS(pre_start, cb->subject, 0, cb->start_match, utf, f);
+
+ /* If a lookbehind is involved, the current position may be earlier than the
+ match start. If so, use the match start instead. */
+
+ current_position = (cb->current_position >= cb->start_match)?
+ cb->current_position : cb->start_match;
+
+ /* The subject between the match start and the current position. */
+
+ PCHARS(post_start, cb->subject, cb->start_match,
+ current_position - cb->start_match, utf, f);
+
+ /* Print from the current position to the end. */
+
+ PCHARSV(cb->subject, current_position, cb->subject_length - current_position,
+ utf, f);
+
+ /* Calculate the total subject printed length (no print). */
+
+ PCHARS(subject_length, cb->subject, 0, cb->subject_length, utf, NULL);
+
+ if (f != NULL) fprintf(f, "\n");
+
+ /* For automatic callouts, show the pattern offset. Otherwise, for a
+ numerical callout whose number has not already been shown with captured
+ strings, show the number here. A callout with a string argument has been
+ displayed above. */
+
+ if (cb->callout_number == 255)
+ {
+ fprintf(outfile, "%+3d ", (int)cb->pattern_position);
+ if (cb->pattern_position > 99) fprintf(outfile, "\n ");
+ }
+ else
+ {
+ if (callout_capture || cb->callout_string != NULL) fprintf(outfile, " ");
+ else fprintf(outfile, "%3d ", cb->callout_number);
+ }
+
+ /* Now show position indicators */
+
+ for (i = 0; i < pre_start; i++) fprintf(outfile, " ");
+ fprintf(outfile, "^");
+
+ if (post_start > 0)
+ {
+ for (i = 0; i < post_start - 1; i++) fprintf(outfile, " ");
+ fprintf(outfile, "^");
+ }
+
+ for (i = 0; i < subject_length - pre_start - post_start + 4; i++)
+ fprintf(outfile, " ");
+
+ if (cb->next_item_length != 0)
+ fprintf(outfile, "%.*s", (int)(cb->next_item_length),
+ pbuffer8 + cb->pattern_position);
+ else
+ fprintf(outfile, "End of pattern");
+
+ fprintf(outfile, "\n");
+ }
+
+first_callout = FALSE;
+
+/* Show any mark info */
+
+if (cb->mark != last_callout_mark)
+ {
+ if (cb->mark == NULL)
+ fprintf(outfile, "Latest Mark: <unset>\n");
+ else
+ {
+ fprintf(outfile, "Latest Mark: ");
+ PCHARSV(cb->mark, 0, -1, utf, outfile);
+ putc('\n', outfile);
+ }
+ last_callout_mark = cb->mark;
+ }
+
+/* Show callout data */
+
+if (callout_data_ptr != NULL)
+ {
+ int callout_data = *((int32_t *)callout_data_ptr);
+ if (callout_data != 0)
+ {
+ fprintf(outfile, "Callout data = %d\n", callout_data);
+ return callout_data;
+ }
+ }
+
+/* Keep count and give the appropriate return code */
+
+callout_count++;
+
+if (cb->callout_number == dat_datctl.cerror[0] &&
+ callout_count >= dat_datctl.cerror[1])
+ return PCRE2_ERROR_CALLOUT;
+
+if (cb->callout_number == dat_datctl.cfail[0] &&
+ callout_count >= dat_datctl.cfail[1])
+ return 1;
+
+return 0;
+}
+
+
+
+/*************************************************
+* Handle *MARK and copy/get tests *
+*************************************************/
+
+/* This function is called after complete and partial matches. It runs the
+tests for substring extraction.
+
+Arguments:
+ utf TRUE for utf
+ capcount return from pcre2_match()
+
+Returns: FALSE if print_error_message() fails
+*/
+
+static BOOL
+copy_and_get(BOOL utf, int capcount)
+{
+int i;
+uint8_t *nptr;
+
+/* Test copy strings by number */
+
+for (i = 0; i < MAXCPYGET && dat_datctl.copy_numbers[i] >= 0; i++)
+ {
+ int rc;
+ PCRE2_SIZE length, length2;
+ uint32_t copybuffer[256];
+ uint32_t n = (uint32_t)(dat_datctl.copy_numbers[i]);
+ length = sizeof(copybuffer)/code_unit_size;
+ PCRE2_SUBSTRING_COPY_BYNUMBER(rc, match_data, n, copybuffer, &length);
+ if (rc < 0)
+ {
+ fprintf(outfile, "Copy substring %d failed (%d): ", n, rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else
+ {
+ PCRE2_SUBSTRING_LENGTH_BYNUMBER(rc, match_data, n, &length2);
+ if (rc < 0)
+ {
+ fprintf(outfile, "Get substring %d length failed (%d): ", n, rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else if (length2 != length)
+ {
+ fprintf(outfile, "Mismatched substring lengths: %"
+ SIZ_FORM " %" SIZ_FORM "\n", SIZ_CAST length, SIZ_CAST length2);
+ }
+ fprintf(outfile, "%2dC ", n);
+ PCHARSV(copybuffer, 0, length, utf, outfile);
+ fprintf(outfile, " (%" SIZ_FORM ")\n", SIZ_CAST length);
+ }
+ }
+
+/* Test copy strings by name */
+
+nptr = dat_datctl.copy_names;
+for (;;)
+ {
+ int rc;
+ int groupnumber;
+ PCRE2_SIZE length, length2;
+ uint32_t copybuffer[256];
+ int namelen = strlen((const char *)nptr);
+#if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32
+ PCRE2_SIZE cnl = namelen;
+#endif
+ if (namelen == 0) break;
+
+#ifdef SUPPORT_PCRE2_8
+ if (test_mode == PCRE8_MODE) strcpy((char *)pbuffer8, (char *)nptr);
+#endif
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE)(void)to16(nptr, utf, &cnl);
+#endif
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl);
+#endif
+
+ PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer);
+ if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING)
+ fprintf(outfile, "Number not found for group '%s'\n", nptr);
+
+ length = sizeof(copybuffer)/code_unit_size;
+ PCRE2_SUBSTRING_COPY_BYNAME(rc, match_data, pbuffer, copybuffer, &length);
+ if (rc < 0)
+ {
+ fprintf(outfile, "Copy substring '%s' failed (%d): ", nptr, rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else
+ {
+ PCRE2_SUBSTRING_LENGTH_BYNAME(rc, match_data, pbuffer, &length2);
+ if (rc < 0)
+ {
+ fprintf(outfile, "Get substring '%s' length failed (%d): ", nptr, rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else if (length2 != length)
+ {
+ fprintf(outfile, "Mismatched substring lengths: %"
+ SIZ_FORM " %" SIZ_FORM "\n", SIZ_CAST length, SIZ_CAST length2);
+ }
+ fprintf(outfile, " C ");
+ PCHARSV(copybuffer, 0, length, utf, outfile);
+ fprintf(outfile, " (%" SIZ_FORM ") %s", SIZ_CAST length, nptr);
+ if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber);
+ else fprintf(outfile, " (non-unique)\n");
+ }
+ nptr += namelen + 1;
+ }
+
+/* Test get strings by number */
+
+for (i = 0; i < MAXCPYGET && dat_datctl.get_numbers[i] >= 0; i++)
+ {
+ int rc;
+ PCRE2_SIZE length;
+ void *gotbuffer;
+ uint32_t n = (uint32_t)(dat_datctl.get_numbers[i]);
+ PCRE2_SUBSTRING_GET_BYNUMBER(rc, match_data, n, &gotbuffer, &length);
+ if (rc < 0)
+ {
+ fprintf(outfile, "Get substring %d failed (%d): ", n, rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else
+ {
+ fprintf(outfile, "%2dG ", n);
+ PCHARSV(gotbuffer, 0, length, utf, outfile);
+ fprintf(outfile, " (%" SIZ_FORM ")\n", SIZ_CAST length);
+ PCRE2_SUBSTRING_FREE(gotbuffer);
+ }
+ }
+
+/* Test get strings by name */
+
+nptr = dat_datctl.get_names;
+for (;;)
+ {
+ PCRE2_SIZE length;
+ void *gotbuffer;
+ int rc;
+ int groupnumber;
+ int namelen = strlen((const char *)nptr);
+#if defined SUPPORT_PCRE2_16 || defined SUPPORT_PCRE2_32
+ PCRE2_SIZE cnl = namelen;
+#endif
+ if (namelen == 0) break;
+
+#ifdef SUPPORT_PCRE2_8
+ if (test_mode == PCRE8_MODE) strcpy((char *)pbuffer8, (char *)nptr);
+#endif
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE)(void)to16(nptr, utf, &cnl);
+#endif
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE)(void)to32(nptr, utf, &cnl);
+#endif
+
+ PCRE2_SUBSTRING_NUMBER_FROM_NAME(groupnumber, compiled_code, pbuffer);
+ if (groupnumber < 0 && groupnumber != PCRE2_ERROR_NOUNIQUESUBSTRING)
+ fprintf(outfile, "Number not found for group '%s'\n", nptr);
+
+ PCRE2_SUBSTRING_GET_BYNAME(rc, match_data, pbuffer, &gotbuffer, &length);
+ if (rc < 0)
+ {
+ fprintf(outfile, "Get substring '%s' failed (%d): ", nptr, rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else
+ {
+ fprintf(outfile, " G ");
+ PCHARSV(gotbuffer, 0, length, utf, outfile);
+ fprintf(outfile, " (%" SIZ_FORM ") %s", SIZ_CAST length, nptr);
+ if (groupnumber >= 0) fprintf(outfile, " (group %d)\n", groupnumber);
+ else fprintf(outfile, " (non-unique)\n");
+ PCRE2_SUBSTRING_FREE(gotbuffer);
+ }
+ nptr += namelen + 1;
+ }
+
+/* Test getting the complete list of captured strings. */
+
+if ((dat_datctl.control & CTL_GETALL) != 0)
+ {
+ int rc;
+ void **stringlist;
+ PCRE2_SIZE *lengths;
+ PCRE2_SUBSTRING_LIST_GET(rc, match_data, &stringlist, &lengths);
+ if (rc < 0)
+ {
+ fprintf(outfile, "get substring list failed (%d): ", rc);
+ if (!print_error_message(rc, "", "\n")) return FALSE;
+ }
+ else
+ {
+ for (i = 0; i < capcount; i++)
+ {
+ fprintf(outfile, "%2dL ", i);
+ PCHARSV(stringlist[i], 0, lengths[i], utf, outfile);
+ putc('\n', outfile);
+ }
+ if (stringlist[i] != NULL)
+ fprintf(outfile, "string list not terminated by NULL\n");
+ PCRE2_SUBSTRING_LIST_FREE(stringlist);
+ }
+ }
+
+return TRUE;
+}
+
+
+
+/*************************************************
+* Process a data line *
+*************************************************/
+
+/* The line is in buffer; it will not be empty.
+
+Arguments: none
+
+Returns: PR_OK continue processing next line
+ PR_SKIP skip to a blank line
+ PR_ABEND abort the pcre2test run
+*/
+
+static int
+process_data(void)
+{
+PCRE2_SIZE len, ulen, arg_ulen;
+uint32_t gmatched;
+uint32_t c, k;
+uint32_t g_notempty = 0;
+uint8_t *p, *pp, *start_rep;
+size_t needlen;
+void *use_dat_context;
+BOOL utf;
+BOOL subject_literal;
+PCRE2_SIZE ovecsave[3];
+
+#ifdef SUPPORT_PCRE2_8
+uint8_t *q8 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_16
+uint16_t *q16 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_32
+uint32_t *q32 = NULL;
+#endif
+
+subject_literal = (pat_patctl.control2 & CTL2_SUBJECT_LITERAL) != 0;
+
+/* Copy the default context and data control blocks to the active ones. Then
+copy from the pattern the controls that can be set in either the pattern or the
+data. This allows them to be overridden in the data line. We do not do this for
+options because those that are common apply separately to compiling and
+matching. */
+
+DATCTXCPY(dat_context, default_dat_context);
+memcpy(&dat_datctl, &def_datctl, sizeof(datctl));
+dat_datctl.control |= (pat_patctl.control & CTL_ALLPD);
+dat_datctl.control2 |= (pat_patctl.control2 & CTL2_ALLPD);
+strcpy((char *)dat_datctl.replacement, (char *)pat_patctl.replacement);
+if (dat_datctl.jitstack == 0) dat_datctl.jitstack = pat_patctl.jitstack;
+
+/* Initialize for scanning the data line. */
+
+#ifdef SUPPORT_PCRE2_8
+utf = ((((pat_patctl.control & CTL_POSIX) != 0)?
+ ((pcre2_real_code_8 *)preg.re_pcre2_code)->overall_options :
+ FLD(compiled_code, overall_options)) & PCRE2_UTF) != 0;
+#else
+utf = (FLD(compiled_code, overall_options) & PCRE2_UTF) != 0;
+#endif
+
+start_rep = NULL;
+len = strlen((const char *)buffer);
+while (len > 0 && isspace(buffer[len-1])) len--;
+buffer[len] = 0;
+p = buffer;
+while (isspace(*p)) p++;
+
+/* Check that the data is well-formed UTF-8 if we're in UTF mode. To create
+invalid input to pcre2_match(), you must use \x?? or \x{} sequences. */
+
+if (utf)
+ {
+ uint8_t *q;
+ uint32_t cc;
+ int n = 1;
+ for (q = p; n > 0 && *q; q += n) n = utf82ord(q, &cc);
+ if (n <= 0)
+ {
+ fprintf(outfile, "** Failed: invalid UTF-8 string cannot be used as input "
+ "in UTF mode\n");
+ return PR_OK;
+ }
+ }
+
+#ifdef SUPPORT_VALGRIND
+/* Mark the dbuffer as addressable but undefined again. */
+if (dbuffer != NULL)
+ {
+ VALGRIND_MAKE_MEM_UNDEFINED(dbuffer, dbuffer_size);
+ }
+#endif
+
+/* Allocate a buffer to hold the data line; len+1 is an upper bound on
+the number of code units that will be needed (though the buffer may have to be
+extended if replication is involved). */
+
+needlen = (size_t)((len+1) * code_unit_size);
+if (dbuffer == NULL || needlen >= dbuffer_size)
+ {
+ while (needlen >= dbuffer_size) dbuffer_size *= 2;
+ dbuffer = (uint8_t *)realloc(dbuffer, dbuffer_size);
+ if (dbuffer == NULL)
+ {
+ fprintf(stderr, "pcre2test: realloc(%d) failed\n", (int)dbuffer_size);
+ exit(1);
+ }
+ }
+SETCASTPTR(q, dbuffer); /* Sets q8, q16, or q32, as appropriate. */
+
+/* Scan the data line, interpreting data escapes, and put the result into a
+buffer of the appropriate width. In UTF mode, input is always UTF-8; otherwise,
+in 16- and 32-bit modes, it can be forced to UTF-8 by the utf8_input modifier.
+*/
+
+while ((c = *p++) != 0)
+ {
+ int32_t i = 0;
+ size_t replen;
+
+ /* ] may mark the end of a replicated sequence */
+
+ if (c == ']' && start_rep != NULL)
+ {
+ long li;
+ char *endptr;
+ size_t qoffset = CAST8VAR(q) - dbuffer;
+ size_t rep_offset = start_rep - dbuffer;
+
+ if (*p++ != '{')
+ {
+ fprintf(outfile, "** Expected '{' after \\[....]\n");
+ return PR_OK;
+ }
+
+ li = strtol((const char *)p, &endptr, 10);
+ if (S32OVERFLOW(li))
+ {
+ fprintf(outfile, "** Repeat count too large\n");
+ return PR_OK;
+ }
+
+ p = (uint8_t *)endptr;
+ if (*p++ != '}')
+ {
+ fprintf(outfile, "** Expected '}' after \\[...]{...\n");
+ return PR_OK;
+ }
+
+ i = (int32_t)li;
+ if (i-- == 0)
+ {
+ fprintf(outfile, "** Zero repeat not allowed\n");
+ return PR_OK;
+ }
+
+ replen = CAST8VAR(q) - start_rep;
+ needlen += replen * i;
+
+ if (needlen >= dbuffer_size)
+ {
+ while (needlen >= dbuffer_size) dbuffer_size *= 2;
+ dbuffer = (uint8_t *)realloc(dbuffer, dbuffer_size);
+ if (dbuffer == NULL)
+ {
+ fprintf(stderr, "pcre2test: realloc(%d) failed\n", (int)dbuffer_size);
+ exit(1);
+ }
+ SETCASTPTR(q, dbuffer + qoffset);
+ start_rep = dbuffer + rep_offset;
+ }
+
+ while (i-- > 0)
+ {
+ memcpy(CAST8VAR(q), start_rep, replen);
+ SETPLUS(q, replen/code_unit_size);
+ }
+
+ start_rep = NULL;
+ continue;
+ }
+
+ /* Handle a non-escaped character. In non-UTF 32-bit mode with utf8_input
+ set, do the fudge for setting the top bit. */
+
+ if (c != '\\' || subject_literal)
+ {
+ uint32_t topbit = 0;
+ if (test_mode == PCRE32_MODE && c == 0xff && *p != 0)
+ {
+ topbit = 0x80000000;
+ c = *p++;
+ }
+ if ((utf || (pat_patctl.control & CTL_UTF8_INPUT) != 0) &&
+ HASUTF8EXTRALEN(c)) { GETUTF8INC(c, p); }
+ c |= topbit;
+ }
+
+ /* Handle backslash escapes */
+
+ else switch ((c = *p++))
+ {
+ case '\\': break;
+ case 'a': c = CHAR_BEL; break;
+ case 'b': c = '\b'; break;
+ case 'e': c = CHAR_ESC; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c -= '0';
+ while (i++ < 2 && isdigit(*p) && *p != '8' && *p != '9')
+ c = c * 8 + *p++ - '0';
+ break;
+
+ case 'o':
+ if (*p == '{')
+ {
+ uint8_t *pt = p;
+ c = 0;
+ for (pt++; isdigit(*pt) && *pt != '8' && *pt != '9'; pt++)
+ {
+ if (++i == 12)
+ fprintf(outfile, "** Too many octal digits in \\o{...} item; "
+ "using only the first twelve.\n");
+ else c = c * 8 + *pt - '0';
+ }
+ if (*pt == '}') p = pt + 1;
+ else fprintf(outfile, "** Missing } after \\o{ (assumed)\n");
+ }
+ break;
+
+ case 'x':
+ if (*p == '{')
+ {
+ uint8_t *pt = p;
+ c = 0;
+
+ /* We used to have "while (isxdigit(*(++pt)))" here, but it fails
+ when isxdigit() is a macro that refers to its argument more than
+ once. This is banned by the C Standard, but apparently happens in at
+ least one MacOS environment. */
+
+ for (pt++; isxdigit(*pt); pt++)
+ {
+ if (++i == 9)
+ fprintf(outfile, "** Too many hex digits in \\x{...} item; "
+ "using only the first eight.\n");
+ else c = c * 16 + tolower(*pt) - ((isdigit(*pt))? '0' : 'a' - 10);
+ }
+ if (*pt == '}')
+ {
+ p = pt + 1;
+ break;
+ }
+ /* Not correct form for \x{...}; fall through */
+ }
+
+ /* \x without {} always defines just one byte in 8-bit mode. This
+ allows UTF-8 characters to be constructed byte by byte, and also allows
+ invalid UTF-8 sequences to be made. Just copy the byte in UTF-8 mode.
+ Otherwise, pass it down as data. */
+
+ c = 0;
+ while (i++ < 2 && isxdigit(*p))
+ {
+ c = c * 16 + tolower(*p) - ((isdigit(*p))? '0' : 'a' - 10);
+ p++;
+ }
+#if defined SUPPORT_PCRE2_8
+ if (utf && (test_mode == PCRE8_MODE))
+ {
+ *q8++ = c;
+ continue;
+ }
+#endif
+ break;
+
+ case 0: /* \ followed by EOF allows for an empty line */
+ p--;
+ continue;
+
+ case '=': /* \= terminates the data, starts modifiers */
+ goto ENDSTRING;
+
+ case '[': /* \[ introduces a replicated character sequence */
+ if (start_rep != NULL)
+ {
+ fprintf(outfile, "** Nested replication is not supported\n");
+ return PR_OK;
+ }
+ start_rep = CAST8VAR(q);
+ continue;
+
+ default:
+ if (isalnum(c))
+ {
+ fprintf(outfile, "** Unrecognized escape sequence \"\\%c\"\n", c);
+ return PR_OK;
+ }
+ }
+
+ /* We now have a character value in c that may be greater than 255.
+ In 8-bit mode we convert to UTF-8 if we are in UTF mode. Values greater
+ than 127 in UTF mode must have come from \x{...} or octal constructs
+ because values from \x.. get this far only in non-UTF mode. */
+
+#ifdef SUPPORT_PCRE2_8
+ if (test_mode == PCRE8_MODE)
+ {
+ if (utf)
+ {
+ if (c > 0x7fffffff)
+ {
+ fprintf(outfile, "** Character \\x{%x} is greater than 0x7fffffff "
+ "and so cannot be converted to UTF-8\n", c);
+ return PR_OK;
+ }
+ q8 += ord2utf8(c, q8);
+ }
+ else
+ {
+ if (c > 0xffu)
+ {
+ fprintf(outfile, "** Character \\x{%x} is greater than 255 "
+ "and UTF-8 mode is not enabled.\n", c);
+ fprintf(outfile, "** Truncation will probably give the wrong "
+ "result.\n");
+ }
+ *q8++ = c;
+ }
+ }
+#endif
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE)
+ {
+ if (utf)
+ {
+ if (c > 0x10ffffu)
+ {
+ fprintf(outfile, "** Failed: character \\x{%x} is greater than "
+ "0x10ffff and so cannot be converted to UTF-16\n", c);
+ return PR_OK;
+ }
+ else if (c >= 0x10000u)
+ {
+ c-= 0x10000u;
+ *q16++ = 0xD800 | (c >> 10);
+ *q16++ = 0xDC00 | (c & 0x3ff);
+ }
+ else
+ *q16++ = c;
+ }
+ else
+ {
+ if (c > 0xffffu)
+ {
+ fprintf(outfile, "** Character \\x{%x} is greater than 0xffff "
+ "and UTF-16 mode is not enabled.\n", c);
+ fprintf(outfile, "** Truncation will probably give the wrong "
+ "result.\n");
+ }
+
+ *q16++ = c;
+ }
+ }
+#endif
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE)
+ {
+ *q32++ = c;
+ }
+#endif
+ }
+
+ENDSTRING:
+SET(*q, 0);
+len = CASTVAR(uint8_t *, q) - dbuffer; /* Length in bytes */
+ulen = len/code_unit_size; /* Length in code units */
+arg_ulen = ulen; /* Value to use in match arg */
+
+/* If the string was terminated by \= we must now interpret modifiers. */
+
+if (p[-1] != 0 && !decode_modifiers(p, CTX_DAT, NULL, &dat_datctl))
+ return PR_OK;
+
+/* Check for mutually exclusive modifiers. At present, these are all in the
+first control word. */
+
+for (k = 0; k < sizeof(exclusive_dat_controls)/sizeof(uint32_t); k++)
+ {
+ c = dat_datctl.control & exclusive_dat_controls[k];
+ if (c != 0 && c != (c & (~c+1)))
+ {
+ show_controls(c, 0, "** Not allowed together:");
+ fprintf(outfile, "\n");
+ return PR_OK;
+ }
+ }
+
+if (pat_patctl.replacement[0] != 0 &&
+ (dat_datctl.control & CTL_NULLCONTEXT) != 0)
+ {
+ fprintf(outfile, "** Replacement text is not supported with null_context.\n");
+ return PR_OK;
+ }
+
+/* We now have the subject in dbuffer, with len containing the byte length, and
+ulen containing the code unit length, with a copy in arg_ulen for use in match
+function arguments (this gets changed to PCRE2_ZERO_TERMINATED when the
+zero_terminate modifier is present).
+
+Move the data to the end of the buffer so that a read over the end can be
+caught by valgrind or other means. If we have explicit valgrind support, mark
+the unused start of the buffer unaddressable. If we are using the POSIX
+interface, or testing zero-termination, we must include the terminating zero in
+the usable data. */
+
+c = code_unit_size * (((pat_patctl.control & CTL_POSIX) +
+ (dat_datctl.control & CTL_ZERO_TERMINATE) != 0)? 1:0);
+pp = memmove(dbuffer + dbuffer_size - len - c, dbuffer, len + c);
+#ifdef SUPPORT_VALGRIND
+ VALGRIND_MAKE_MEM_NOACCESS(dbuffer, dbuffer_size - (len + c));
+#endif
+
+/* Now pp points to the subject string. POSIX matching is only possible in
+8-bit mode, and it does not support timing or other fancy features. Some were
+checked at compile time, but we need to check the match-time settings here. */
+
+#ifdef SUPPORT_PCRE2_8
+if ((pat_patctl.control & CTL_POSIX) != 0)
+ {
+ int rc;
+ int eflags = 0;
+ regmatch_t *pmatch = NULL;
+ const char *msg = "** Ignored with POSIX interface:";
+
+ if (dat_datctl.cerror[0] != CFORE_UNSET || dat_datctl.cerror[1] != CFORE_UNSET)
+ prmsg(&msg, "callout_error");
+ if (dat_datctl.cfail[0] != CFORE_UNSET || dat_datctl.cfail[1] != CFORE_UNSET)
+ prmsg(&msg, "callout_fail");
+ if (dat_datctl.copy_numbers[0] >= 0 || dat_datctl.copy_names[0] != 0)
+ prmsg(&msg, "copy");
+ if (dat_datctl.get_numbers[0] >= 0 || dat_datctl.get_names[0] != 0)
+ prmsg(&msg, "get");
+ if (dat_datctl.jitstack != 0) prmsg(&msg, "jitstack");
+ if (dat_datctl.offset != 0) prmsg(&msg, "offset");
+
+ if ((dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS) != 0)
+ {
+ fprintf(outfile, "%s", msg);
+ show_match_options(dat_datctl.options & ~POSIX_SUPPORTED_MATCH_OPTIONS);
+ msg = "";
+ }
+ if ((dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS) != 0 ||
+ (dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2) != 0)
+ {
+ show_controls(dat_datctl.control & ~POSIX_SUPPORTED_MATCH_CONTROLS,
+ dat_datctl.control2 & ~POSIX_SUPPORTED_MATCH_CONTROLS2, msg);
+ msg = "";
+ }
+
+ if (msg[0] == 0) fprintf(outfile, "\n");
+
+ if (dat_datctl.oveccount > 0)
+ {
+ pmatch = (regmatch_t *)malloc(sizeof(regmatch_t) * dat_datctl.oveccount);
+ if (pmatch == NULL)
+ {
+ fprintf(outfile, "** Failed to get memory for recording matching "
+ "information (size set = %du)\n", dat_datctl.oveccount);
+ return PR_OK;
+ }
+ }
+
+ if (dat_datctl.startend[0] != CFORE_UNSET)
+ {
+ pmatch[0].rm_so = dat_datctl.startend[0];
+ pmatch[0].rm_eo = (dat_datctl.startend[1] != 0)?
+ dat_datctl.startend[1] : len;
+ eflags |= REG_STARTEND;
+ }
+
+ if ((dat_datctl.options & PCRE2_NOTBOL) != 0) eflags |= REG_NOTBOL;
+ if ((dat_datctl.options & PCRE2_NOTEOL) != 0) eflags |= REG_NOTEOL;
+ if ((dat_datctl.options & PCRE2_NOTEMPTY) != 0) eflags |= REG_NOTEMPTY;
+
+ rc = regexec(&preg, (const char *)pp, dat_datctl.oveccount, pmatch, eflags);
+ if (rc != 0)
+ {
+ (void)regerror(rc, &preg, (char *)pbuffer8, pbuffer8_size);
+ fprintf(outfile, "No match: POSIX code %d: %s\n", rc, pbuffer8);
+ }
+ else if ((pat_patctl.control & CTL_POSIX_NOSUB) != 0)
+ fprintf(outfile, "Matched with REG_NOSUB\n");
+ else if (dat_datctl.oveccount == 0)
+ fprintf(outfile, "Matched without capture\n");
+ else
+ {
+ size_t i, j;
+ size_t last_printed = (size_t)dat_datctl.oveccount;
+ for (i = 0; i < (size_t)dat_datctl.oveccount; i++)
+ {
+ if (pmatch[i].rm_so >= 0)
+ {
+ PCRE2_SIZE start = pmatch[i].rm_so;
+ PCRE2_SIZE end = pmatch[i].rm_eo;
+ for (j = last_printed + 1; j < i; j++)
+ fprintf(outfile, "%2d: <unset>\n", (int)j);
+ last_printed = i;
+ if (start > end)
+ {
+ start = pmatch[i].rm_eo;
+ end = pmatch[i].rm_so;
+ fprintf(outfile, "Start of matched string is beyond its end - "
+ "displaying from end to start.\n");
+ }
+ fprintf(outfile, "%2d: ", (int)i);
+ PCHARSV(pp, start, end - start, utf, outfile);
+ fprintf(outfile, "\n");
+
+ if ((i == 0 && (dat_datctl.control & CTL_AFTERTEXT) != 0) ||
+ (dat_datctl.control & CTL_ALLAFTERTEXT) != 0)
+ {
+ fprintf(outfile, "%2d+ ", (int)i);
+ /* Note: don't use the start/end variables here because we want to
+ show the text from what is reported as the end. */
+ PCHARSV(pp, pmatch[i].rm_eo, len - pmatch[i].rm_eo, utf, outfile);
+ fprintf(outfile, "\n"); }
+ }
+ }
+ }
+ free(pmatch);
+ return PR_OK;
+ }
+#endif /* SUPPORT_PCRE2_8 */
+
+ /* Handle matching via the native interface. Check for consistency of
+modifiers. */
+
+if (dat_datctl.startend[0] != CFORE_UNSET)
+ fprintf(outfile, "** \\=posix_startend ignored for non-POSIX matching\n");
+
+/* ALLUSEDTEXT is not supported with JIT, but JIT is not used with DFA
+matching, even if the JIT compiler was used. */
+
+if ((dat_datctl.control & (CTL_ALLUSEDTEXT|CTL_DFA)) == CTL_ALLUSEDTEXT &&
+ FLD(compiled_code, executable_jit) != NULL)
+ {
+ fprintf(outfile, "** Showing all consulted text is not supported by JIT: ignored\n");
+ dat_datctl.control &= ~CTL_ALLUSEDTEXT;
+ }
+
+/* Handle passing the subject as zero-terminated. */
+
+if ((dat_datctl.control & CTL_ZERO_TERMINATE) != 0)
+ arg_ulen = PCRE2_ZERO_TERMINATED;
+
+/* The nullcontext modifier is used to test calling pcre2_[jit_]match() with a
+NULL context. */
+
+use_dat_context = ((dat_datctl.control & CTL_NULLCONTEXT) != 0)?
+ NULL : PTR(dat_context);
+
+/* Enable display of malloc/free if wanted. We can do this only if either the
+pattern or the subject is processed with a context. */
+
+show_memory = (dat_datctl.control & CTL_MEMORY) != 0;
+
+if (show_memory &&
+ (pat_patctl.control & dat_datctl.control & CTL_NULLCONTEXT) != 0)
+ fprintf(outfile, "** \\=memory requires either a pattern or a subject "
+ "context: ignored\n");
+
+/* Create and assign a JIT stack if requested. */
+
+if (dat_datctl.jitstack != 0)
+ {
+ if (dat_datctl.jitstack != jit_stack_size)
+ {
+ PCRE2_JIT_STACK_FREE(jit_stack);
+ PCRE2_JIT_STACK_CREATE(jit_stack, 1, dat_datctl.jitstack * 1024, NULL);
+ jit_stack_size = dat_datctl.jitstack;
+ }
+ PCRE2_JIT_STACK_ASSIGN(dat_context, jit_callback, jit_stack);
+ }
+
+/* Or de-assign */
+
+else if (jit_stack != NULL)
+ {
+ PCRE2_JIT_STACK_ASSIGN(dat_context, NULL, NULL);
+ PCRE2_JIT_STACK_FREE(jit_stack);
+ jit_stack = NULL;
+ jit_stack_size = 0;
+ }
+
+/* When no JIT stack is assigned, we must ensure that there is a JIT callback
+if we want to verify that JIT was actually used. */
+
+if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_stack == NULL)
+ {
+ PCRE2_JIT_STACK_ASSIGN(dat_context, jit_callback, NULL);
+ }
+
+/* Adjust match_data according to size of offsets required. A size of zero
+causes a new match data block to be obtained that exactly fits the pattern. */
+
+if (dat_datctl.oveccount == 0)
+ {
+ PCRE2_MATCH_DATA_FREE(match_data);
+ PCRE2_MATCH_DATA_CREATE_FROM_PATTERN(match_data, compiled_code, NULL);
+ PCRE2_GET_OVECTOR_COUNT(max_oveccount, match_data);
+ }
+else if (dat_datctl.oveccount <= max_oveccount)
+ {
+ SETFLD(match_data, oveccount, dat_datctl.oveccount);
+ }
+else
+ {
+ max_oveccount = dat_datctl.oveccount;
+ PCRE2_MATCH_DATA_FREE(match_data);
+ PCRE2_MATCH_DATA_CREATE(match_data, max_oveccount, NULL);
+ }
+
+if (CASTVAR(void *, match_data) == NULL)
+ {
+ fprintf(outfile, "** Failed to get memory for recording matching "
+ "information (size requested: %d)\n", dat_datctl.oveccount);
+ max_oveccount = 0;
+ return PR_OK;
+ }
+
+/* Replacement processing is ignored for DFA matching. */
+
+if (dat_datctl.replacement[0] != 0 && (dat_datctl.control & CTL_DFA) != 0)
+ {
+ fprintf(outfile, "** Ignored for DFA matching: replace\n");
+ dat_datctl.replacement[0] = 0;
+ }
+
+/* If a replacement string is provided, call pcre2_substitute() instead of one
+of the matching functions. First we have to convert the replacement string to
+the appropriate width. */
+
+if (dat_datctl.replacement[0] != 0)
+ {
+ int rc;
+ uint8_t *pr;
+ uint8_t rbuffer[REPLACE_BUFFSIZE];
+ uint8_t nbuffer[REPLACE_BUFFSIZE];
+ uint32_t xoptions;
+ PCRE2_SIZE rlen, nsize, erroroffset;
+ BOOL badutf = FALSE;
+
+#ifdef SUPPORT_PCRE2_8
+ uint8_t *r8 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_16
+ uint16_t *r16 = NULL;
+#endif
+#ifdef SUPPORT_PCRE2_32
+ uint32_t *r32 = NULL;
+#endif
+
+ if (timeitm)
+ fprintf(outfile, "** Timing is not supported with replace: ignored\n");
+
+ if ((dat_datctl.control & CTL_ALTGLOBAL) != 0)
+ fprintf(outfile, "** Altglobal is not supported with replace: ignored\n");
+
+ xoptions = (((dat_datctl.control & CTL_GLOBAL) == 0)? 0 :
+ PCRE2_SUBSTITUTE_GLOBAL) |
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_EXTENDED) == 0)? 0 :
+ PCRE2_SUBSTITUTE_EXTENDED) |
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_OVERFLOW_LENGTH) == 0)? 0 :
+ PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) |
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNKNOWN_UNSET) == 0)? 0 :
+ PCRE2_SUBSTITUTE_UNKNOWN_UNSET) |
+ (((dat_datctl.control2 & CTL2_SUBSTITUTE_UNSET_EMPTY) == 0)? 0 :
+ PCRE2_SUBSTITUTE_UNSET_EMPTY);
+
+ SETCASTPTR(r, rbuffer); /* Sets r8, r16, or r32, as appropriate. */
+ pr = dat_datctl.replacement;
+
+ /* If the replacement starts with '[<number>]' we interpret that as length
+ value for the replacement buffer. */
+
+ nsize = REPLACE_BUFFSIZE/code_unit_size;
+ if (*pr == '[')
+ {
+ PCRE2_SIZE n = 0;
+ while ((c = *(++pr)) >= CHAR_0 && c <= CHAR_9) n = n * 10 + c - CHAR_0;
+ if (*pr++ != ']')
+ {
+ fprintf(outfile, "Bad buffer size in replacement string\n");
+ return PR_OK;
+ }
+ if (n > nsize)
+ {
+ fprintf(outfile, "Replacement buffer setting (%" SIZ_FORM ") is too "
+ "large (max %" SIZ_FORM ")\n", SIZ_CAST n, SIZ_CAST nsize);
+ return PR_OK;
+ }
+ nsize = n;
+ }
+
+ /* Now copy the replacement string to a buffer of the appropriate width. No
+ escape processing is done for replacements. In UTF mode, check for an invalid
+ UTF-8 input string, and if it is invalid, just copy its code units without
+ UTF interpretation. This provides a means of checking that an invalid string
+ is detected. Otherwise, UTF-8 can be used to include wide characters in a
+ replacement. */
+
+ if (utf) badutf = valid_utf(pr, strlen((const char *)pr), &erroroffset);
+
+ /* Not UTF or invalid UTF-8: just copy the code units. */
+
+ if (!utf || badutf)
+ {
+ while ((c = *pr++) != 0)
+ {
+#ifdef SUPPORT_PCRE2_8
+ if (test_mode == PCRE8_MODE) *r8++ = c;
+#endif
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE) *r16++ = c;
+#endif
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE) *r32++ = c;
+#endif
+ }
+ }
+
+ /* Valid UTF-8 replacement string */
+
+ else while ((c = *pr++) != 0)
+ {
+ if (HASUTF8EXTRALEN(c)) { GETUTF8INC(c, pr); }
+
+#ifdef SUPPORT_PCRE2_8
+ if (test_mode == PCRE8_MODE) r8 += ord2utf8(c, r8);
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE)
+ {
+ if (c >= 0x10000u)
+ {
+ c-= 0x10000u;
+ *r16++ = 0xD800 | (c >> 10);
+ *r16++ = 0xDC00 | (c & 0x3ff);
+ }
+ else *r16++ = c;
+ }
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE) *r32++ = c;
+#endif
+ }
+
+ SET(*r, 0);
+ if ((dat_datctl.control & CTL_ZERO_TERMINATE) != 0)
+ rlen = PCRE2_ZERO_TERMINATED;
+ else
+ rlen = (CASTVAR(uint8_t *, r) - rbuffer)/code_unit_size;
+ PCRE2_SUBSTITUTE(rc, compiled_code, pp, arg_ulen, dat_datctl.offset,
+ dat_datctl.options|xoptions, match_data, dat_context,
+ rbuffer, rlen, nbuffer, &nsize);
+
+ if (rc < 0)
+ {
+ fprintf(outfile, "Failed: error %d", rc);
+ if (rc != PCRE2_ERROR_NOMEMORY && nsize != PCRE2_UNSET)
+ fprintf(outfile, " at offset %ld in replacement", (long int)nsize);
+ fprintf(outfile, ": ");
+ if (!print_error_message(rc, "", "")) return PR_ABEND;
+ if (rc == PCRE2_ERROR_NOMEMORY &&
+ (xoptions & PCRE2_SUBSTITUTE_OVERFLOW_LENGTH) != 0)
+ fprintf(outfile, ": %ld code units are needed", (long int)nsize);
+ }
+ else
+ {
+ fprintf(outfile, "%2d: ", rc);
+ PCHARSV(nbuffer, 0, nsize, utf, outfile);
+ }
+
+ fprintf(outfile, "\n");
+ show_memory = FALSE;
+ return PR_OK;
+ } /* End of substitution handling */
+
+/* When a replacement string is not provided, run a loop for global matching
+with one of the basic matching functions. For altglobal (or first time round
+the loop), set an "unset" value for the previous match info. */
+
+ovecsave[0] = ovecsave[1] = ovecsave[2] = PCRE2_UNSET;
+
+for (gmatched = 0;; gmatched++)
+ {
+ PCRE2_SIZE j;
+ int capcount;
+ PCRE2_SIZE *ovector;
+
+ ovector = FLD(match_data, ovector);
+
+ /* Fill the ovector with junk to detect elements that do not get set
+ when they should be. */
+
+ for (j = 0; j < 2*dat_datctl.oveccount; j++) ovector[j] = JUNK_OFFSET;
+
+ /* When matching is via pcre2_match(), we will detect the use of JIT via the
+ stack callback function. */
+
+ jit_was_used = (pat_patctl.control & CTL_JITFAST) != 0;
+
+ /* Do timing if required. */
+
+ if (timeitm > 0)
+ {
+ int i;
+ clock_t start_time, time_taken;
+
+ if ((dat_datctl.control & CTL_DFA) != 0)
+ {
+ if ((dat_datctl.options & PCRE2_DFA_RESTART) != 0)
+ {
+ fprintf(outfile, "Timing DFA restarts is not supported\n");
+ return PR_OK;
+ }
+ if (dfa_workspace == NULL)
+ dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int));
+ start_time = clock();
+ for (i = 0; i < timeitm; i++)
+ {
+ PCRE2_DFA_MATCH(capcount, compiled_code, pp, arg_ulen,
+ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+ use_dat_context, dfa_workspace, DFA_WS_DIMENSION);
+ }
+ }
+
+ else if ((pat_patctl.control & CTL_JITFAST) != 0)
+ {
+ start_time = clock();
+ for (i = 0; i < timeitm; i++)
+ {
+ PCRE2_JIT_MATCH(capcount, compiled_code, pp, arg_ulen,
+ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+ use_dat_context);
+ }
+ }
+
+ else
+ {
+ start_time = clock();
+ for (i = 0; i < timeitm; i++)
+ {
+ PCRE2_MATCH(capcount, compiled_code, pp, arg_ulen,
+ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+ use_dat_context);
+ }
+ }
+ total_match_time += (time_taken = clock() - start_time);
+ fprintf(outfile, "Match time %.4f milliseconds\n",
+ (((double)time_taken * 1000.0) / (double)timeitm) /
+ (double)CLOCKS_PER_SEC);
+ }
+
+ /* Find the heap, match and depth limits if requested. The depth and heap
+ limits are not relevant for JIT. The return from check_match_limit() is the
+ return from the final call to pcre2_match() or pcre2_dfa_match(). */
+
+ if ((dat_datctl.control & CTL_FINDLIMITS) != 0)
+ {
+ capcount = 0; /* This stops compiler warnings */
+
+ if (FLD(compiled_code, executable_jit) == NULL ||
+ (dat_datctl.options & PCRE2_NO_JIT) != 0)
+ {
+ (void)check_match_limit(pp, arg_ulen, PCRE2_ERROR_HEAPLIMIT, "heap");
+ }
+
+ capcount = check_match_limit(pp, arg_ulen, PCRE2_ERROR_MATCHLIMIT,
+ "match");
+
+ if (FLD(compiled_code, executable_jit) == NULL ||
+ (dat_datctl.options & PCRE2_NO_JIT) != 0 ||
+ (dat_datctl.control & CTL_DFA) != 0)
+ {
+ capcount = check_match_limit(pp, arg_ulen, PCRE2_ERROR_DEPTHLIMIT,
+ "depth");
+ }
+
+ if (capcount == 0)
+ {
+ fprintf(outfile, "Matched, but offsets vector is too small to show all matches\n");
+ capcount = dat_datctl.oveccount;
+ }
+ }
+
+ /* Otherwise just run a single match, setting up a callout if required (the
+ default). There is a copy of the pattern in pbuffer8 for use by callouts. */
+
+ else
+ {
+ if ((dat_datctl.control & CTL_CALLOUT_NONE) == 0)
+ {
+ PCRE2_SET_CALLOUT(dat_context, callout_function,
+ (void *)(&dat_datctl.callout_data));
+ first_callout = TRUE;
+ last_callout_mark = NULL;
+ callout_count = 0;
+ }
+ else
+ {
+ PCRE2_SET_CALLOUT(dat_context, NULL, NULL); /* No callout */
+ }
+
+ /* Run a single DFA or NFA match. */
+
+ if ((dat_datctl.control & CTL_DFA) != 0)
+ {
+ if (dfa_workspace == NULL)
+ dfa_workspace = (int *)malloc(DFA_WS_DIMENSION*sizeof(int));
+ if (dfa_matched++ == 0)
+ dfa_workspace[0] = -1; /* To catch bad restart */
+ PCRE2_DFA_MATCH(capcount, compiled_code, pp, arg_ulen,
+ dat_datctl.offset, dat_datctl.options | g_notempty, match_data,
+ use_dat_context, dfa_workspace, DFA_WS_DIMENSION);
+ if (capcount == 0)
+ {
+ fprintf(outfile, "Matched, but offsets vector is too small to show all matches\n");
+ capcount = dat_datctl.oveccount;
+ }
+ }
+ else
+ {
+ if ((pat_patctl.control & CTL_JITFAST) != 0)
+ PCRE2_JIT_MATCH(capcount, compiled_code, pp, arg_ulen, dat_datctl.offset,
+ dat_datctl.options | g_notempty, match_data, use_dat_context);
+ else
+ PCRE2_MATCH(capcount, compiled_code, pp, arg_ulen, dat_datctl.offset,
+ dat_datctl.options | g_notempty, match_data, use_dat_context);
+ if (capcount == 0)
+ {
+ fprintf(outfile, "Matched, but too many substrings\n");
+ capcount = dat_datctl.oveccount;
+ }
+ }
+ }
+
+ /* The result of the match is now in capcount. First handle a successful
+ match. */
+
+ if (capcount >= 0)
+ {
+ int i;
+ uint32_t oveccount;
+
+ /* This is a check against a lunatic return value. */
+
+ PCRE2_GET_OVECTOR_COUNT(oveccount, match_data);
+ if (capcount > (int)oveccount)
+ {
+ fprintf(outfile,
+ "** PCRE2 error: returned count %d is too big for ovector count %d\n",
+ capcount, oveccount);
+ capcount = oveccount;
+ if ((dat_datctl.control & CTL_ANYGLOB) != 0)
+ {
+ fprintf(outfile, "** Global loop abandoned\n");
+ dat_datctl.control &= ~CTL_ANYGLOB; /* Break g/G loop */
+ }
+ }
+
+ /* If this is not the first time round a global loop, check that the
+ returned string has changed. If it has not, check for an empty string match
+ at different starting offset from the previous match. This is a failed test
+ retry for null-matching patterns that don't match at their starting offset,
+ for example /(?<=\G.)/. A repeated match at the same point is not such a
+ pattern, and must be discarded, and we then proceed to seek a non-null
+ match at the current point. For any other repeated match, there is a bug
+ somewhere and we must break the loop because it will go on for ever. We
+ know that there are always at least two elements in the ovector. */
+
+ if (gmatched > 0 && ovecsave[0] == ovector[0] && ovecsave[1] == ovector[1])
+ {
+ if (ovector[0] == ovector[1] && ovecsave[2] != dat_datctl.offset)
+ {
+ g_notempty = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+ ovecsave[2] = dat_datctl.offset;
+ continue; /* Back to the top of the loop */
+ }
+ fprintf(outfile,
+ "** PCRE2 error: global repeat returned the same string as previous\n");
+ fprintf(outfile, "** Global loop abandoned\n");
+ dat_datctl.control &= ~CTL_ANYGLOB; /* Break g/G loop */
+ }
+
+ /* "allcaptures" requests showing of all captures in the pattern, to check
+ unset ones at the end. It may be set on the pattern or the data. Implement
+ by setting capcount to the maximum. This is not relevant for DFA matching,
+ so ignore it. */
+
+ if ((dat_datctl.control & CTL_ALLCAPTURES) != 0)
+ {
+ uint32_t maxcapcount;
+ if ((dat_datctl.control & CTL_DFA) != 0)
+ {
+ fprintf(outfile, "** Ignored after DFA matching: allcaptures\n");
+ }
+ else
+ {
+ if (pattern_info(PCRE2_INFO_CAPTURECOUNT, &maxcapcount, FALSE) < 0)
+ return PR_SKIP;
+ capcount = maxcapcount + 1; /* Allow for full match */
+ if (capcount > (int)oveccount) capcount = oveccount;
+ }
+ }
+
+ /* Output the captured substrings. Note that, for the matched string,
+ the use of \K in an assertion can make the start later than the end. */
+
+ for (i = 0; i < 2*capcount; i += 2)
+ {
+ PCRE2_SIZE lleft, lmiddle, lright;
+ PCRE2_SIZE start = ovector[i];
+ PCRE2_SIZE end = ovector[i+1];
+
+ if (start > end)
+ {
+ start = ovector[i+1];
+ end = ovector[i];
+ fprintf(outfile, "Start of matched string is beyond its end - "
+ "displaying from end to start.\n");
+ }
+
+ fprintf(outfile, "%2d: ", i/2);
+
+ /* Check for an unset group */
+
+ if (start == PCRE2_UNSET)
+ {
+ fprintf(outfile, "<unset>\n");
+ continue;
+ }
+
+ /* Check for silly offsets, in particular, values that have not been
+ set when they should have been. */
+
+ if (start > ulen || end > ulen)
+ {
+ fprintf(outfile, "ERROR: bad value(s) for offset(s): 0x%lx 0x%lx\n",
+ (unsigned long int)start, (unsigned long int)end);
+ continue;
+ }
+
+ /* When JIT is not being used, ALLUSEDTEXT may be set. (It if is set with
+ JIT, it is disabled above, with a comment.) When the match is done by the
+ interpreter, leftchar and rightchar are available, and if ALLUSEDTEXT is
+ set, and if the leftmost consulted character is before the start of the
+ match or the rightmost consulted character is past the end of the match,
+ we want to show all consulted characters for the main matched string, and
+ indicate which were lookarounds. */
+
+ if (i == 0)
+ {
+ BOOL showallused;
+ PCRE2_SIZE leftchar, rightchar;
+
+ if ((dat_datctl.control & CTL_ALLUSEDTEXT) != 0)
+ {
+ leftchar = FLD(match_data, leftchar);
+ rightchar = FLD(match_data, rightchar);
+ showallused = i == 0 && (leftchar < start || rightchar > end);
+ }
+ else showallused = FALSE;
+
+ if (showallused)
+ {
+ PCHARS(lleft, pp, leftchar, start - leftchar, utf, outfile);
+ PCHARS(lmiddle, pp, start, end - start, utf, outfile);
+ PCHARS(lright, pp, end, rightchar - end, utf, outfile);
+ if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+ fprintf(outfile, " (JIT)");
+ fprintf(outfile, "\n ");
+ for (j = 0; j < lleft; j++) fprintf(outfile, "<");
+ for (j = 0; j < lmiddle; j++) fprintf(outfile, " ");
+ for (j = 0; j < lright; j++) fprintf(outfile, ">");
+ }
+
+ /* When a pattern contains \K, the start of match position may be
+ different to the start of the matched string. When this is the case,
+ show it when requested. */
+
+ else if ((dat_datctl.control & CTL_STARTCHAR) != 0)
+ {
+ PCRE2_SIZE startchar;
+ PCRE2_GET_STARTCHAR(startchar, match_data);
+ PCHARS(lleft, pp, startchar, start - startchar, utf, outfile);
+ PCHARSV(pp, start, end - start, utf, outfile);
+ if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+ fprintf(outfile, " (JIT)");
+ if (startchar != start)
+ {
+ fprintf(outfile, "\n ");
+ for (j = 0; j < lleft; j++) fprintf(outfile, "^");
+ }
+ }
+
+ /* Otherwise, just show the matched string. */
+
+ else
+ {
+ PCHARSV(pp, start, end - start, utf, outfile);
+ if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+ fprintf(outfile, " (JIT)");
+ }
+ }
+
+ /* Not the main matched string. Just show it unadorned. */
+
+ else
+ {
+ PCHARSV(pp, start, end - start, utf, outfile);
+ }
+
+ fprintf(outfile, "\n");
+
+ /* Note: don't use the start/end variables here because we want to
+ show the text from what is reported as the end. */
+
+ if ((dat_datctl.control & CTL_ALLAFTERTEXT) != 0 ||
+ (i == 0 && (dat_datctl.control & CTL_AFTERTEXT) != 0))
+ {
+ fprintf(outfile, "%2d+ ", i/2);
+ PCHARSV(pp, ovector[i+1], ulen - ovector[i+1], utf, outfile);
+ fprintf(outfile, "\n");
+ }
+ }
+
+ /* Output (*MARK) data if requested */
+
+ if ((dat_datctl.control & CTL_MARK) != 0 &&
+ TESTFLD(match_data, mark, !=, NULL))
+ {
+ fprintf(outfile, "MK: ");
+ PCHARSV(CASTFLD(void *, match_data, mark), 0, -1, utf, outfile);
+ fprintf(outfile, "\n");
+ }
+
+ /* Process copy/get strings */
+
+ if (!copy_and_get(utf, capcount)) return PR_ABEND;
+
+ } /* End of handling a successful match */
+
+ /* There was a partial match. The value of ovector[0] is the bumpalong point,
+ that is, startchar, not any \K point that might have been passed. */
+
+ else if (capcount == PCRE2_ERROR_PARTIAL)
+ {
+ PCRE2_SIZE poffset;
+ int backlength;
+ int rubriclength = 0;
+
+ fprintf(outfile, "Partial match");
+ if ((dat_datctl.control & CTL_MARK) != 0 &&
+ TESTFLD(match_data, mark, !=, NULL))
+ {
+ fprintf(outfile, ", mark=");
+ PCHARS(rubriclength, CASTFLD(void *, match_data, mark), 0, -1, utf,
+ outfile);
+ rubriclength += 7;
+ }
+ fprintf(outfile, ": ");
+ rubriclength += 15;
+
+ poffset = backchars(pp, ovector[0], maxlookbehind, utf);
+ PCHARS(backlength, pp, poffset, ovector[0] - poffset, utf, outfile);
+ PCHARSV(pp, ovector[0], ulen - ovector[0], utf, outfile);
+
+ if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+ fprintf(outfile, " (JIT)");
+ fprintf(outfile, "\n");
+
+ if (backlength != 0)
+ {
+ int i;
+ for (i = 0; i < rubriclength; i++) fprintf(outfile, " ");
+ for (i = 0; i < backlength; i++) fprintf(outfile, "<");
+ fprintf(outfile, "\n");
+ }
+
+ /* Process copy/get strings */
+
+ if (!copy_and_get(utf, 1)) return PR_ABEND;
+
+ break; /* Out of the /g loop */
+ } /* End of handling partial match */
+
+ /* Failed to match. If this is a /g or /G loop, we might previously have
+ set g_notempty (to PCRE2_NOTEMPTY_ATSTART|PCRE2_ANCHORED) after a null match.
+ If that is the case, this is not necessarily the end. We want to advance the
+ start offset, and continue. We won't be at the end of the string - that was
+ checked before setting g_notempty. We achieve the effect by pretending that a
+ single character was matched.
+
+ Complication arises in the case when the newline convention is "any", "crlf",
+ or "anycrlf". If the previous match was at the end of a line terminated by
+ CRLF, an advance of one character just passes the CR, whereas we should
+ prefer the longer newline sequence, as does the code in pcre2_match().
+
+ Otherwise, in the case of UTF-8 or UTF-16 matching, the advance must be one
+ character, not one byte. */
+
+ else if (g_notempty != 0) /* There was a previous null match */
+ {
+ uint16_t nl = FLD(compiled_code, newline_convention);
+ PCRE2_SIZE start_offset = dat_datctl.offset; /* Where the match was */
+ PCRE2_SIZE end_offset = start_offset + 1;
+
+ if ((nl == PCRE2_NEWLINE_CRLF || nl == PCRE2_NEWLINE_ANY ||
+ nl == PCRE2_NEWLINE_ANYCRLF) &&
+ start_offset < ulen - 1 &&
+ CODE_UNIT(pp, start_offset) == '\r' &&
+ CODE_UNIT(pp, end_offset) == '\n')
+ end_offset++;
+
+ else if (utf && test_mode != PCRE32_MODE)
+ {
+ if (test_mode == PCRE8_MODE)
+ {
+ for (; end_offset < ulen; end_offset++)
+ if ((((PCRE2_SPTR8)pp)[end_offset] & 0xc0) != 0x80) break;
+ }
+ else /* 16-bit mode */
+ {
+ for (; end_offset < ulen; end_offset++)
+ if ((((PCRE2_SPTR16)pp)[end_offset] & 0xfc00) != 0xdc00) break;
+ }
+ }
+
+ SETFLDVEC(match_data, ovector, 0, start_offset);
+ SETFLDVEC(match_data, ovector, 1, end_offset);
+ } /* End of handling null match in a global loop */
+
+ /* A "normal" match failure. There will be a negative error number in
+ capcount. */
+
+ else
+ {
+ switch(capcount)
+ {
+ case PCRE2_ERROR_NOMATCH:
+ if (gmatched == 0)
+ {
+ fprintf(outfile, "No match");
+ if ((dat_datctl.control & CTL_MARK) != 0 &&
+ TESTFLD(match_data, mark, !=, NULL))
+ {
+ fprintf(outfile, ", mark = ");
+ PCHARSV(CASTFLD(void *, match_data, mark), 0, -1, utf, outfile);
+ }
+ if ((pat_patctl.control & CTL_JITVERIFY) != 0 && jit_was_used)
+ fprintf(outfile, " (JIT)");
+ fprintf(outfile, "\n");
+ }
+ break;
+
+ case PCRE2_ERROR_BADUTFOFFSET:
+ fprintf(outfile, "Error %d (bad UTF-%d offset)\n", capcount, test_mode);
+ break;
+
+ default:
+ fprintf(outfile, "Failed: error %d: ", capcount);
+ if (!print_error_message(capcount, "", "")) return PR_ABEND;
+ if (capcount <= PCRE2_ERROR_UTF8_ERR1 &&
+ capcount >= PCRE2_ERROR_UTF32_ERR2)
+ {
+ PCRE2_SIZE startchar;
+ PCRE2_GET_STARTCHAR(startchar, match_data);
+ fprintf(outfile, " at offset %" SIZ_FORM, SIZ_CAST startchar);
+ }
+ fprintf(outfile, "\n");
+ break;
+ }
+
+ break; /* Out of the /g loop */
+ } /* End of failed match handling */
+
+ /* Control reaches here in two circumstances: (a) after a match, and (b)
+ after a non-match that immediately followed a match on an empty string when
+ doing a global search. Such a match is done with PCRE2_NOTEMPTY_ATSTART and
+ PCRE2_ANCHORED set in g_notempty. The code above turns it into a fake match
+ of one character. So effectively we get here only after a match. If we
+ are not doing a global search, we are done. */
+
+ if ((dat_datctl.control & CTL_ANYGLOB) == 0) break; else
+ {
+ PCRE2_SIZE match_offset = FLD(match_data, ovector)[0];
+ PCRE2_SIZE end_offset = FLD(match_data, ovector)[1];
+
+ /* We must now set up for the next iteration of a global search. If we have
+ matched an empty string, first check to see if we are at the end of the
+ subject. If so, the loop is over. Otherwise, mimic what Perl's /g option
+ does. Set PCRE2_NOTEMPTY_ATSTART and PCRE2_ANCHORED and try the match again
+ at the same point. If this fails it will be picked up above, where a fake
+ match is set up so that at this point we advance to the next character.
+
+ However, in order to cope with patterns that never match at their starting
+ offset (e.g. /(?<=\G.)/) we don't do this when the match offset is greater
+ than the starting offset. This means there will be a retry with the
+ starting offset at the match offset. If this returns the same match again,
+ it is picked up above and ignored, and the special action is then taken. */
+
+ if (match_offset == end_offset)
+ {
+ if (end_offset == ulen) break; /* End of subject */
+ if (match_offset <= dat_datctl.offset)
+ g_notempty = PCRE2_NOTEMPTY_ATSTART | PCRE2_ANCHORED;
+ }
+
+ /* However, even after matching a non-empty string, there is still one
+ tricky case. If a pattern contains \K within a lookbehind assertion at the
+ start, the end of the matched string can be at the offset where the match
+ started. In the case of a normal /g iteration without special action, this
+ leads to a loop that keeps on returning the same substring. The loop would
+ be caught above, but we really want to move on to the next match. */
+
+ else
+ {
+ g_notempty = 0; /* Set for a "normal" repeat */
+ if ((dat_datctl.control & CTL_GLOBAL) != 0)
+ {
+ PCRE2_SIZE startchar;
+ PCRE2_GET_STARTCHAR(startchar, match_data);
+ if (end_offset <= startchar)
+ {
+ if (startchar >= ulen) break; /* End of subject */
+ end_offset = startchar + 1;
+ if (utf && test_mode != PCRE32_MODE)
+ {
+ if (test_mode == PCRE8_MODE)
+ {
+ for (; end_offset < ulen; end_offset++)
+ if ((((PCRE2_SPTR8)pp)[end_offset] & 0xc0) != 0x80) break;
+ }
+ else /* 16-bit mode */
+ {
+ for (; end_offset < ulen; end_offset++)
+ if ((((PCRE2_SPTR16)pp)[end_offset] & 0xfc00) != 0xdc00) break;
+ }
+ }
+ }
+ }
+ }
+
+ /* For a normal global (/g) iteration, save the current ovector[0,1] and
+ the starting offset so that we can check that they do change each time.
+ Otherwise a matching bug that returns the same string causes an infinite
+ loop. It has happened! Then update the start offset, leaving other
+ parameters alone. */
+
+ if ((dat_datctl.control & CTL_GLOBAL) != 0)
+ {
+ ovecsave[0] = ovector[0];
+ ovecsave[1] = ovector[1];
+ ovecsave[2] = dat_datctl.offset;
+ dat_datctl.offset = end_offset;
+ }
+
+ /* For altglobal, just update the pointer and length. */
+
+ else
+ {
+ pp += end_offset * code_unit_size;
+ len -= end_offset * code_unit_size;
+ ulen -= end_offset;
+ if (arg_ulen != PCRE2_ZERO_TERMINATED) arg_ulen -= end_offset;
+ }
+ }
+ } /* End of global loop */
+
+show_memory = FALSE;
+return PR_OK;
+}
+
+
+
+
+/*************************************************
+* Print PCRE2 version *
+*************************************************/
+
+static void
+print_version(FILE *f)
+{
+VERSION_TYPE *vp;
+fprintf(f, "PCRE2 version ");
+for (vp = version; *vp != 0; vp++) fprintf(f, "%c", *vp);
+fprintf(f, "\n");
+}
+
+
+
+/*************************************************
+* Print Unicode version *
+*************************************************/
+
+static void
+print_unicode_version(FILE *f)
+{
+VERSION_TYPE *vp;
+fprintf(f, "Unicode version ");
+for (vp = uversion; *vp != 0; vp++) fprintf(f, "%c", *vp);
+}
+
+
+
+/*************************************************
+* Print JIT target *
+*************************************************/
+
+static void
+print_jit_target(FILE *f)
+{
+VERSION_TYPE *vp;
+for (vp = jittarget; *vp != 0; vp++) fprintf(f, "%c", *vp);
+}
+
+
+
+/*************************************************
+* Print newline configuration *
+*************************************************/
+
+/* Output is always to stdout.
+
+Arguments:
+ rc the return code from PCRE2_CONFIG_NEWLINE
+ isc TRUE if called from "-C newline"
+Returns: nothing
+*/
+
+static void
+print_newline_config(uint32_t optval, BOOL isc)
+{
+if (!isc) printf(" Newline sequence is ");
+if (optval < sizeof(newlines)/sizeof(char *))
+ printf("%s\n", newlines[optval]);
+else
+ printf("a non-standard value: %d\n", optval);
+}
+
+
+
+/*************************************************
+* Usage function *
+*************************************************/
+
+static void
+usage(void)
+{
+printf("Usage: pcre2test [options] [<input file> [<output file>]]\n\n");
+printf("Input and output default to stdin and stdout.\n");
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+printf("If input is a terminal, readline() is used to read from it.\n");
+#else
+printf("This version of pcre2test is not linked with readline().\n");
+#endif
+printf("\nOptions:\n");
+#ifdef SUPPORT_PCRE2_8
+printf(" -8 use the 8-bit library\n");
+#endif
+#ifdef SUPPORT_PCRE2_16
+printf(" -16 use the 16-bit library\n");
+#endif
+#ifdef SUPPORT_PCRE2_32
+printf(" -32 use the 32-bit library\n");
+#endif
+printf(" -ac set default pattern modifier PCRE2_AUTO_CALLOUT\n");
+printf(" -AC as -ac, but also set subject 'callout_extra' modifier\n");
+printf(" -b set default pattern modifier 'fullbincode'\n");
+printf(" -C show PCRE2 compile-time options and exit\n");
+printf(" -C arg show a specific compile-time option and exit with its\n");
+printf(" value if numeric (else 0). The arg can be:\n");
+printf(" backslash-C use of \\C is enabled [0, 1]\n");
+printf(" bsr \\R type [ANYCRLF, ANY]\n");
+printf(" ebcdic compiled for EBCDIC character code [0,1]\n");
+printf(" ebcdic-nl NL code if compiled for EBCDIC\n");
+printf(" jit just-in-time compiler supported [0, 1]\n");
+printf(" linksize internal link size [2, 3, 4]\n");
+printf(" newline newline type [CR, LF, CRLF, ANYCRLF, ANY, NUL]\n");
+printf(" pcre2-8 8 bit library support enabled [0, 1]\n");
+printf(" pcre2-16 16 bit library support enabled [0, 1]\n");
+printf(" pcre2-32 32 bit library support enabled [0, 1]\n");
+printf(" unicode Unicode and UTF support enabled [0, 1]\n");
+printf(" -d set default pattern modifier 'debug'\n");
+printf(" -dfa set default subject modifier 'dfa'\n");
+printf(" -error <n,m,..> show messages for error numbers, then exit\n");
+printf(" -help show usage information\n");
+printf(" -i set default pattern modifier 'info'\n");
+printf(" -jit set default pattern modifier 'jit'\n");
+printf(" -jitverify set default pattern modifier 'jitverify'\n");
+printf(" -LM list pattern and subject modifiers, then exit\n");
+printf(" -q quiet: do not output PCRE2 version number at start\n");
+printf(" -pattern <s> set default pattern modifier fields\n");
+printf(" -subject <s> set default subject modifier fields\n");
+printf(" -S <n> set stack size to <n> mebibytes\n");
+printf(" -t [<n>] time compilation and execution, repeating <n> times\n");
+printf(" -tm [<n>] time execution (matching) only, repeating <n> times\n");
+printf(" -T same as -t, but show total times at the end\n");
+printf(" -TM same as -tm, but show total time at the end\n");
+printf(" -version show PCRE2 version and exit\n");
+}
+
+
+
+/*************************************************
+* Handle -C option *
+*************************************************/
+
+/* This option outputs configuration options and sets an appropriate return
+code when asked for a single option. The code is abstracted into a separate
+function because of its size. Use whichever pcre2_config() function is
+available.
+
+Argument: an option name or NULL
+Returns: the return code
+*/
+
+static int
+c_option(const char *arg)
+{
+uint32_t optval;
+unsigned int i = COPTLISTCOUNT;
+int yield = 0;
+
+if (arg != NULL && arg[0] != CHAR_MINUS)
+ {
+ for (i = 0; i < COPTLISTCOUNT; i++)
+ if (strcmp(arg, coptlist[i].name) == 0) break;
+
+ if (i >= COPTLISTCOUNT)
+ {
+ fprintf(stderr, "** Unknown -C option '%s'\n", arg);
+ return 0;
+ }
+
+ switch (coptlist[i].type)
+ {
+ case CONF_BSR:
+ (void)PCRE2_CONFIG(coptlist[i].value, &optval);
+ printf("%s\n", (optval == PCRE2_BSR_ANYCRLF)? "ANYCRLF" : "ANY");
+ break;
+
+ case CONF_FIX:
+ yield = coptlist[i].value;
+ printf("%d\n", yield);
+ break;
+
+ case CONF_FIZ:
+ optval = coptlist[i].value;
+ printf("%d\n", optval);
+ break;
+
+ case CONF_INT:
+ (void)PCRE2_CONFIG(coptlist[i].value, &yield);
+ printf("%d\n", yield);
+ break;
+
+ case CONF_NL:
+ (void)PCRE2_CONFIG(coptlist[i].value, &optval);
+ print_newline_config(optval, TRUE);
+ break;
+ }
+
+/* For VMS, return the value by setting a symbol, for certain values only. */
+
+#ifdef __VMS
+ if (copytlist[i].type == CONF_FIX || coptlist[i].type == CONF_INT)
+ {
+ char ucname[16];
+ strcpy(ucname, coptlist[i].name);
+ for (i = 0; ucname[i] != 0; i++) ucname[i] = toupper[ucname[i]];
+ vms_setsymbol(ucname, 0, optval);
+ }
+#endif
+
+ return yield;
+ }
+
+/* No argument for -C: output all configuration information. */
+
+print_version(stdout);
+printf("Compiled with\n");
+
+#ifdef EBCDIC
+printf(" EBCDIC code support: LF is 0x%02x\n", CHAR_LF);
+#if defined NATIVE_ZOS
+printf(" EBCDIC code page %s or similar\n", pcrz_cpversion());
+#endif
+#endif
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_COMPILED_WIDTHS, &optval);
+if (optval & 1) printf(" 8-bit support\n");
+if (optval & 2) printf(" 16-bit support\n");
+if (optval & 4) printf(" 32-bit support\n");
+
+#ifdef SUPPORT_VALGRIND
+printf(" Valgrind support\n");
+#endif
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_UNICODE, &optval);
+if (optval != 0)
+ {
+ printf(" UTF and UCP support (");
+ print_unicode_version(stdout);
+ printf(")\n");
+ }
+else printf(" No Unicode support\n");
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_JIT, &optval);
+if (optval != 0)
+ {
+ printf(" Just-in-time compiler support: ");
+ print_jit_target(stdout);
+ printf("\n");
+ }
+else
+ {
+ printf(" No just-in-time compiler support\n");
+ }
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_NEWLINE, &optval);
+print_newline_config(optval, FALSE);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_BSR, &optval);
+printf(" \\R matches %s\n",
+ (optval == PCRE2_BSR_ANYCRLF)? "CR, LF, or CRLF only" :
+ "all Unicode newlines");
+(void)PCRE2_CONFIG(PCRE2_CONFIG_NEVER_BACKSLASH_C, &optval);
+printf(" \\C is %ssupported\n", optval? "not ":"");
+(void)PCRE2_CONFIG(PCRE2_CONFIG_LINKSIZE, &optval);
+printf(" Internal link size = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_PARENSLIMIT, &optval);
+printf(" Parentheses nest limit = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_HEAPLIMIT, &optval);
+printf(" Default heap limit = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_MATCHLIMIT, &optval);
+printf(" Default match limit = %d\n", optval);
+(void)PCRE2_CONFIG(PCRE2_CONFIG_DEPTHLIMIT, &optval);
+printf(" Default depth limit = %d\n", optval);
+return 0;
+}
+
+
+
+/*************************************************
+* Display one modifier *
+*************************************************/
+
+static void
+display_one_modifier(modstruct *m, BOOL for_pattern)
+{
+uint32_t c = (!for_pattern && (m->which == MOD_PND || m->which == MOD_PNDP))?
+ '*' : ' ';
+printf("%c%s", c, m->name);
+}
+
+
+
+/*************************************************
+* Display pattern or subject modifiers *
+*************************************************/
+
+/* In order to print in two columns, first scan without printing to get a list
+of the modifiers that are required.
+
+Arguments:
+ for_pattern TRUE for pattern modifiers, FALSE for subject modifiers
+ title string to be used in title
+
+Returns: nothing
+*/
+
+static void
+display_selected_modifiers(BOOL for_pattern, const char *title)
+{
+uint32_t i, j;
+uint32_t n = 0;
+uint32_t list[MODLISTCOUNT];
+
+for (i = 0; i < MODLISTCOUNT; i++)
+ {
+ BOOL is_pattern = TRUE;
+ modstruct *m = modlist + i;
+
+ switch (m->which)
+ {
+ case MOD_CTC: /* Compile context */
+ case MOD_PAT: /* Pattern */
+ case MOD_PATP: /* Pattern, OK for Perl-compatible test */
+ break;
+
+ /* The MOD_PND and MOD_PNDP modifiers are precisely those that affect
+ subjects, but can be given with a pattern. We list them as subject
+ modifiers, but marked with an asterisk.*/
+
+ case MOD_CTM: /* Match context */
+ case MOD_DAT: /* Subject line */
+ case MOD_PND: /* As PD, but not default pattern */
+ case MOD_PNDP: /* As PND, OK for Perl-compatible test */
+ is_pattern = FALSE;
+ break;
+
+ default: printf("** Unknown type for modifier '%s'\n", m->name);
+ /* Fall through */
+ case MOD_PD: /* Pattern or subject */
+ case MOD_PDP: /* As PD, OK for Perl-compatible test */
+ is_pattern = for_pattern;
+ break;
+ }
+
+ if (for_pattern == is_pattern) list[n++] = i;
+ }
+
+/* Now print from the list in two columns. */
+
+printf("-------------- %s MODIFIERS --------------\n", title);
+
+for (i = 0, j = (n+1)/2; i < (n+1)/2; i++, j++)
+ {
+ modstruct *m = modlist + list[i];
+ display_one_modifier(m, for_pattern);
+ if (j < n)
+ {
+ uint32_t k = 27 - strlen(m->name);
+ while (k-- > 0) printf(" ");
+ display_one_modifier(modlist + list[j], for_pattern);
+ }
+ printf("\n");
+ }
+}
+
+
+
+/*************************************************
+* Display the list of modifiers *
+*************************************************/
+
+static void
+display_modifiers(void)
+{
+printf(
+ "An asterisk on a subject modifier means that it may be given on a pattern\n"
+ "line, in order to apply to all subjects matched by that pattern. Modifiers\n"
+ "that are listed for both patterns and subjects have different effects in\n"
+ "each case.\n\n");
+display_selected_modifiers(TRUE, "PATTERN");
+printf("\n");
+display_selected_modifiers(FALSE, "SUBJECT");
+}
+
+
+
+/*************************************************
+* Main Program *
+*************************************************/
+
+int
+main(int argc, char **argv)
+{
+uint32_t temp;
+uint32_t yield = 0;
+uint32_t op = 1;
+BOOL notdone = TRUE;
+BOOL quiet = FALSE;
+BOOL showtotaltimes = FALSE;
+BOOL skipping = FALSE;
+char *arg_subject = NULL;
+char *arg_pattern = NULL;
+char *arg_error = NULL;
+
+/* The offsets to the options and control bits fields of the pattern and data
+control blocks must be the same so that common options and controls such as
+"anchored" or "memory" can work for either of them from a single table entry.
+We cannot test this till runtime because "offsetof" does not work in the
+preprocessor. */
+
+if (PO(options) != DO(options) || PO(control) != DO(control) ||
+ PO(control2) != DO(control2))
+ {
+ fprintf(stderr, "** Coding error: "
+ "options and control offsets for pattern and data must be the same.\n");
+ return 1;
+ }
+
+/* Get the PCRE2 and Unicode version number and JIT target information, at the
+same time checking that a request for the length gives the same answer. Also
+check lengths for non-string items. */
+
+if (PCRE2_CONFIG(PCRE2_CONFIG_VERSION, NULL) !=
+ PCRE2_CONFIG(PCRE2_CONFIG_VERSION, version) ||
+
+ PCRE2_CONFIG(PCRE2_CONFIG_UNICODE_VERSION, NULL) !=
+ PCRE2_CONFIG(PCRE2_CONFIG_UNICODE_VERSION, uversion) ||
+
+ PCRE2_CONFIG(PCRE2_CONFIG_JITTARGET, NULL) !=
+ PCRE2_CONFIG(PCRE2_CONFIG_JITTARGET, jittarget) ||
+
+ PCRE2_CONFIG(PCRE2_CONFIG_UNICODE, NULL) != sizeof(uint32_t) ||
+ PCRE2_CONFIG(PCRE2_CONFIG_MATCHLIMIT, NULL) != sizeof(uint32_t))
+ {
+ fprintf(stderr, "** Error in pcre2_config(): bad length\n");
+ return 1;
+ }
+
+/* Check that bad options are diagnosed. */
+
+if (PCRE2_CONFIG(999, NULL) != PCRE2_ERROR_BADOPTION ||
+ PCRE2_CONFIG(999, &temp) != PCRE2_ERROR_BADOPTION)
+ {
+ fprintf(stderr, "** Error in pcre2_config(): bad option not diagnosed\n");
+ return 1;
+ }
+
+/* This configuration option is now obsolete, but running a quick check ensures
+that its code is covered. */
+
+(void)PCRE2_CONFIG(PCRE2_CONFIG_STACKRECURSE, &temp);
+
+/* Get buffers from malloc() so that valgrind will check their misuse when
+debugging. They grow automatically when very long lines are read. The 16-
+and 32-bit buffers (pbuffer16, pbuffer32) are obtained only if needed. */
+
+buffer = (uint8_t *)malloc(pbuffer8_size);
+pbuffer8 = (uint8_t *)malloc(pbuffer8_size);
+
+/* The following _setmode() stuff is some Windows magic that tells its runtime
+library to translate CRLF into a single LF character. At least, that's what
+I've been told: never having used Windows I take this all on trust. Originally
+it set 0x8000, but then I was advised that _O_BINARY was better. */
+
+#if defined(_WIN32) || defined(WIN32)
+_setmode( _fileno( stdout ), _O_BINARY );
+#endif
+
+/* Initialization that does not depend on the running mode. */
+
+locale_name[0] = 0;
+
+memset(&def_patctl, 0, sizeof(patctl));
+def_patctl.convert_type = CONVERT_UNSET;
+
+memset(&def_datctl, 0, sizeof(datctl));
+def_datctl.oveccount = DEFAULT_OVECCOUNT;
+def_datctl.copy_numbers[0] = -1;
+def_datctl.get_numbers[0] = -1;
+def_datctl.startend[0] = def_datctl.startend[1] = CFORE_UNSET;
+def_datctl.cerror[0] = def_datctl.cerror[1] = CFORE_UNSET;
+def_datctl.cfail[0] = def_datctl.cfail[1] = CFORE_UNSET;
+
+/* Scan command line options. */
+
+while (argc > 1 && argv[op][0] == '-' && argv[op][1] != 0)
+ {
+ char *endptr;
+ char *arg = argv[op];
+ unsigned long uli;
+
+ /* List modifiers and exit. */
+
+ if (strcmp(arg, "-LM") == 0)
+ {
+ display_modifiers();
+ goto EXIT;
+ }
+
+ /* Display and/or set return code for configuration options. */
+
+ if (strcmp(arg, "-C") == 0)
+ {
+ yield = c_option(argv[op + 1]);
+ goto EXIT;
+ }
+
+ /* Select operating mode. Ensure that pcre2_config() is called in 16-bit
+ and 32-bit modes because that won't happen naturally when 8-bit is also
+ configured. Also call some other functions that are not otherwise used. This
+ means that a coverage report won't claim there are uncalled functions. */
+
+ if (strcmp(arg, "-8") == 0)
+ {
+#ifdef SUPPORT_PCRE2_8
+ test_mode = PCRE8_MODE;
+ (void)pcre2_set_bsr_8(pat_context8, 999);
+ (void)pcre2_set_newline_8(pat_context8, 999);
+#else
+ fprintf(stderr,
+ "** This version of PCRE2 was built without 8-bit support\n");
+ exit(1);
+#endif
+ }
+
+ else if (strcmp(arg, "-16") == 0)
+ {
+#ifdef SUPPORT_PCRE2_16
+ test_mode = PCRE16_MODE;
+ (void)pcre2_config_16(PCRE2_CONFIG_VERSION, NULL);
+ (void)pcre2_set_bsr_16(pat_context16, 999);
+ (void)pcre2_set_newline_16(pat_context16, 999);
+#else
+ fprintf(stderr,
+ "** This version of PCRE2 was built without 16-bit support\n");
+ exit(1);
+#endif
+ }
+
+ else if (strcmp(arg, "-32") == 0)
+ {
+#ifdef SUPPORT_PCRE2_32
+ test_mode = PCRE32_MODE;
+ (void)pcre2_config_32(PCRE2_CONFIG_VERSION, NULL);
+ (void)pcre2_set_bsr_32(pat_context32, 999);
+ (void)pcre2_set_newline_32(pat_context32, 999);
+#else
+ fprintf(stderr,
+ "** This version of PCRE2 was built without 32-bit support\n");
+ exit(1);
+#endif
+ }
+
+ /* Set quiet (no version verification) */
+
+ else if (strcmp(arg, "-q") == 0) quiet = TRUE;
+
+ /* Set system stack size */
+
+ else if (strcmp(arg, "-S") == 0 && argc > 2 &&
+ ((uli = strtoul(argv[op+1], &endptr, 10)), *endptr == 0))
+ {
+#if defined(_WIN32) || defined(WIN32) || defined(__minix) || defined(NATIVE_ZOS) || defined(__VMS) || defined(__K1__)
+ fprintf(stderr, "pcre2test: -S is not supported on this OS\n");
+ exit(1);
+#else
+ int rc;
+ uint32_t stack_size;
+ struct rlimit rlim;
+ if (U32OVERFLOW(uli))
+ {
+ fprintf(stderr, "** Argument for -S is too big\n");
+ exit(1);
+ }
+ stack_size = (uint32_t)uli;
+ getrlimit(RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = stack_size * 1024 * 1024;
+ if (rlim.rlim_cur > rlim.rlim_max)
+ {
+ fprintf(stderr,
+ "pcre2test: requested stack size %luMiB is greater than hard limit "
+ "%luMiB\n", (unsigned long int)stack_size,
+ (unsigned long int)(rlim.rlim_max));
+ exit(1);
+ }
+ rc = setrlimit(RLIMIT_STACK, &rlim);
+ if (rc != 0)
+ {
+ fprintf(stderr, "pcre2test: setting stack size %luMiB failed: %s\n",
+ (unsigned long int)stack_size, strerror(errno));
+ exit(1);
+ }
+ op++;
+ argc--;
+#endif
+ }
+
+ /* Set some common pattern and subject controls */
+
+ else if (strcmp(arg, "-AC") == 0)
+ {
+ def_patctl.options |= PCRE2_AUTO_CALLOUT;
+ def_datctl.control2 |= CTL2_CALLOUT_EXTRA;
+ }
+ else if (strcmp(arg, "-ac") == 0) def_patctl.options |= PCRE2_AUTO_CALLOUT;
+ else if (strcmp(arg, "-b") == 0) def_patctl.control |= CTL_FULLBINCODE;
+ else if (strcmp(arg, "-d") == 0) def_patctl.control |= CTL_DEBUG;
+ else if (strcmp(arg, "-dfa") == 0) def_datctl.control |= CTL_DFA;
+ else if (strcmp(arg, "-i") == 0) def_patctl.control |= CTL_INFO;
+ else if (strcmp(arg, "-jit") == 0 || strcmp(arg, "-jitverify") == 0)
+ {
+ if (arg[4] != 0) def_patctl.control |= CTL_JITVERIFY;
+ def_patctl.jit = 7; /* full & partial */
+#ifndef SUPPORT_JIT
+ fprintf(stderr, "** Warning: JIT support is not available: "
+ "-jit[verify] calls functions that do nothing.\n");
+#endif
+ }
+
+ /* Set timing parameters */
+
+ else if (strcmp(arg, "-t") == 0 || strcmp(arg, "-tm") == 0 ||
+ strcmp(arg, "-T") == 0 || strcmp(arg, "-TM") == 0)
+ {
+ int both = arg[2] == 0;
+ showtotaltimes = arg[1] == 'T';
+ if (argc > 2 && (uli = strtoul(argv[op+1], &endptr, 10), *endptr == 0))
+ {
+ if (U32OVERFLOW(uli))
+ {
+ fprintf(stderr, "** Argument for %s is too big\n", arg);
+ exit(1);
+ }
+ timeitm = (int)uli;
+ op++;
+ argc--;
+ }
+ else timeitm = LOOPREPEAT;
+ if (both) timeit = timeitm;
+ }
+
+ /* Give help */
+
+ else if (strcmp(arg, "-help") == 0 ||
+ strcmp(arg, "--help") == 0)
+ {
+ usage();
+ goto EXIT;
+ }
+
+ /* Show version */
+
+ else if (strcmp(arg, "-version") == 0 ||
+ strcmp(arg, "--version") == 0)
+ {
+ print_version(stdout);
+ goto EXIT;
+ }
+
+ /* The following options save their data for processing once we know what
+ the running mode is. */
+
+ else if (strcmp(arg, "-error") == 0)
+ {
+ arg_error = argv[op+1];
+ goto CHECK_VALUE_EXISTS;
+ }
+
+ else if (strcmp(arg, "-subject") == 0)
+ {
+ arg_subject = argv[op+1];
+ goto CHECK_VALUE_EXISTS;
+ }
+
+ else if (strcmp(arg, "-pattern") == 0)
+ {
+ arg_pattern = argv[op+1];
+ CHECK_VALUE_EXISTS:
+ if (argc <= 2)
+ {
+ fprintf(stderr, "** Missing value for %s\n", arg);
+ yield = 1;
+ goto EXIT;
+ }
+ op++;
+ argc--;
+ }
+
+ /* Unrecognized option */
+
+ else
+ {
+ fprintf(stderr, "** Unknown or malformed option '%s'\n", arg);
+ usage();
+ yield = 1;
+ goto EXIT;
+ }
+ op++;
+ argc--;
+ }
+
+/* If -error was present, get the error numbers, show the messages, and exit.
+We wait to do this until we know which mode we are in. */
+
+if (arg_error != NULL)
+ {
+ int len;
+ int errcode;
+ char *endptr;
+
+/* Ensure the relevant non-8-bit buffer is available. Ensure that it is at
+least 128 code units, because it is used for retrieving error messages. */
+
+#ifdef SUPPORT_PCRE2_16
+ if (test_mode == PCRE16_MODE)
+ {
+ pbuffer16_size = 256;
+ pbuffer16 = (uint16_t *)malloc(pbuffer16_size);
+ if (pbuffer16 == NULL)
+ {
+ fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer16\n",
+ SIZ_CAST pbuffer16_size);
+ yield = 1;
+ goto EXIT;
+ }
+ }
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+ if (test_mode == PCRE32_MODE)
+ {
+ pbuffer32_size = 512;
+ pbuffer32 = (uint32_t *)malloc(pbuffer32_size);
+ if (pbuffer32 == NULL)
+ {
+ fprintf(stderr, "pcre2test: malloc(%" SIZ_FORM ") failed for pbuffer32\n",
+ SIZ_CAST pbuffer32_size);
+ yield = 1;
+ goto EXIT;
+ }
+ }
+#endif
+
+ /* Loop along a list of error numbers. */
+
+ for (;;)
+ {
+ errcode = strtol(arg_error, &endptr, 10);
+ if (*endptr != 0 && *endptr != CHAR_COMMA)
+ {
+ fprintf(stderr, "** '%s' is not a valid error number list\n", arg_error);
+ yield = 1;
+ goto EXIT;
+ }
+ printf("Error %d: ", errcode);
+ PCRE2_GET_ERROR_MESSAGE(len, errcode, pbuffer);
+ if (len < 0)
+ {
+ switch (len)
+ {
+ case PCRE2_ERROR_BADDATA:
+ printf("PCRE2_ERROR_BADDATA (unknown error number)");
+ break;
+
+ case PCRE2_ERROR_NOMEMORY:
+ printf("PCRE2_ERROR_NOMEMORY (buffer too small)");
+ break;
+
+ default:
+ printf("Unexpected return (%d) from pcre2_get_error_message()", len);
+ break;
+ }
+ }
+ else
+ {
+ PCHARSV(CASTVAR(void *, pbuffer), 0, len, FALSE, stdout);
+ }
+ printf("\n");
+ if (*endptr == 0) goto EXIT;
+ arg_error = endptr + 1;
+ }
+ /* Control never reaches here */
+ } /* End of -error handling */
+
+/* Initialize things that cannot be done until we know which test mode we are
+running in. Exercise the general context copying function, which is not
+otherwise used. */
+
+code_unit_size = test_mode/8;
+max_oveccount = DEFAULT_OVECCOUNT;
+
+/* Use macros to save a lot of duplication. */
+
+#define CREATECONTEXTS \
+ G(general_context,BITS) = G(pcre2_general_context_create_,BITS)(&my_malloc, &my_free, NULL); \
+ G(general_context_copy,BITS) = G(pcre2_general_context_copy_,BITS)(G(general_context,BITS)); \
+ G(default_pat_context,BITS) = G(pcre2_compile_context_create_,BITS)(G(general_context,BITS)); \
+ G(pat_context,BITS) = G(pcre2_compile_context_copy_,BITS)(G(default_pat_context,BITS)); \
+ G(default_dat_context,BITS) = G(pcre2_match_context_create_,BITS)(G(general_context,BITS)); \
+ G(dat_context,BITS) = G(pcre2_match_context_copy_,BITS)(G(default_dat_context,BITS)); \
+ G(default_con_context,BITS) = G(pcre2_convert_context_create_,BITS)(G(general_context,BITS)); \
+ G(con_context,BITS) = G(pcre2_convert_context_copy_,BITS)(G(default_con_context,BITS)); \
+ G(match_data,BITS) = G(pcre2_match_data_create_,BITS)(max_oveccount, G(general_context,BITS))
+
+#define CONTEXTTESTS \
+ (void)G(pcre2_set_compile_extra_options_,BITS)(G(pat_context,BITS), 0); \
+ (void)G(pcre2_set_max_pattern_length_,BITS)(G(pat_context,BITS), 0); \
+ (void)G(pcre2_set_offset_limit_,BITS)(G(dat_context,BITS), 0); \
+ (void)G(pcre2_set_recursion_memory_management_,BITS)(G(dat_context,BITS), my_malloc, my_free, NULL)
+
+/* Call the appropriate functions for the current mode, and exercise some
+functions that are not otherwise called. */
+
+#ifdef SUPPORT_PCRE2_8
+#undef BITS
+#define BITS 8
+if (test_mode == PCRE8_MODE)
+ {
+ CREATECONTEXTS;
+ CONTEXTTESTS;
+ }
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+#undef BITS
+#define BITS 16
+if (test_mode == PCRE16_MODE)
+ {
+ CREATECONTEXTS;
+ CONTEXTTESTS;
+ }
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+#undef BITS
+#define BITS 32
+if (test_mode == PCRE32_MODE)
+ {
+ CREATECONTEXTS;
+ CONTEXTTESTS;
+ }
+#endif
+
+/* Set a default parentheses nest limit that is large enough to run the
+standard tests (this also exercises the function). */
+
+PCRE2_SET_PARENS_NEST_LIMIT(default_pat_context, PARENS_NEST_DEFAULT);
+
+/* Handle command line modifier settings, sending any error messages to
+stderr. We need to know the mode before modifying the context, and it is tidier
+to do them all in the same way. */
+
+outfile = stderr;
+if ((arg_pattern != NULL &&
+ !decode_modifiers((uint8_t *)arg_pattern, CTX_DEFPAT, &def_patctl, NULL)) ||
+ (arg_subject != NULL &&
+ !decode_modifiers((uint8_t *)arg_subject, CTX_DEFDAT, NULL, &def_datctl)))
+ {
+ yield = 1;
+ goto EXIT;
+ }
+
+/* Sort out the input and output files, defaulting to stdin/stdout. */
+
+infile = stdin;
+outfile = stdout;
+
+if (argc > 1 && strcmp(argv[op], "-") != 0)
+ {
+ infile = fopen(argv[op], INPUT_MODE);
+ if (infile == NULL)
+ {
+ printf("** Failed to open '%s': %s\n", argv[op], strerror(errno));
+ yield = 1;
+ goto EXIT;
+ }
+ }
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (INTERACTIVE(infile)) using_history();
+#endif
+
+if (argc > 2)
+ {
+ outfile = fopen(argv[op+1], OUTPUT_MODE);
+ if (outfile == NULL)
+ {
+ printf("** Failed to open '%s': %s\n", argv[op+1], strerror(errno));
+ yield = 1;
+ goto EXIT;
+ }
+ }
+
+/* Output a heading line unless quiet, then process input lines. */
+
+if (!quiet) print_version(outfile);
+
+SET(compiled_code, NULL);
+
+#ifdef SUPPORT_PCRE2_8
+preg.re_pcre2_code = NULL;
+preg.re_match_data = NULL;
+#endif
+
+while (notdone)
+ {
+ uint8_t *p;
+ int rc = PR_OK;
+ BOOL expectdata = TEST(compiled_code, !=, NULL);
+#ifdef SUPPORT_PCRE2_8
+ expectdata |= preg.re_pcre2_code != NULL;
+#endif
+
+ if (extend_inputline(infile, buffer, expectdata? "data> " : " re> ") == NULL)
+ break;
+ if (!INTERACTIVE(infile)) fprintf(outfile, "%s", (char *)buffer);
+ fflush(outfile);
+ p = buffer;
+
+ /* If we have a pattern set up for testing, or we are skipping after a
+ compile failure, a blank line terminates this test. */
+
+ if (expectdata || skipping)
+ {
+ while (isspace(*p)) p++;
+ if (*p == 0)
+ {
+#ifdef SUPPORT_PCRE2_8
+ if (preg.re_pcre2_code != NULL)
+ {
+ regfree(&preg);
+ preg.re_pcre2_code = NULL;
+ preg.re_match_data = NULL;
+ }
+#endif /* SUPPORT_PCRE2_8 */
+ if (TEST(compiled_code, !=, NULL))
+ {
+ SUB1(pcre2_code_free, compiled_code);
+ SET(compiled_code, NULL);
+ }
+ skipping = FALSE;
+ setlocale(LC_CTYPE, "C");
+ }
+
+ /* Otherwise, if we are not skipping, and the line is not a data comment
+ line starting with "\=", process a data line. */
+
+ else if (!skipping && !(p[0] == '\\' && p[1] == '=' && isspace(p[2])))
+ {
+ rc = process_data();
+ }
+ }
+
+ /* We do not have a pattern set up for testing. Lines starting with # are
+ either comments or special commands. Blank lines are ignored. Otherwise, the
+ line must start with a valid delimiter. It is then processed as a pattern
+ line. A copy of the pattern is left in pbuffer8 for use by callouts. Under
+ valgrind, make the unused part of the buffer undefined, to catch overruns. */
+
+ else if (*p == '#')
+ {
+ if (isspace(p[1]) || p[1] == '!' || p[1] == 0) continue;
+ rc = process_command();
+ }
+
+ else if (strchr("/!\"'`%&-=_:;,@~", *p) != NULL)
+ {
+ rc = process_pattern();
+ dfa_matched = 0;
+ }
+
+ else
+ {
+ while (isspace(*p)) p++;
+ if (*p != 0)
+ {
+ fprintf(outfile, "** Invalid pattern delimiter '%c' (x%x).\n", *buffer,
+ *buffer);
+ rc = PR_SKIP;
+ }
+ }
+
+ if (rc == PR_SKIP && !INTERACTIVE(infile)) skipping = TRUE;
+ else if (rc == PR_ABEND)
+ {
+ fprintf(outfile, "** pcre2test run abandoned\n");
+ yield = 1;
+ goto EXIT;
+ }
+ }
+
+/* Finish off a normal run. */
+
+if (INTERACTIVE(infile)) fprintf(outfile, "\n");
+
+if (showtotaltimes)
+ {
+ const char *pad = "";
+ fprintf(outfile, "--------------------------------------\n");
+ if (timeit > 0)
+ {
+ fprintf(outfile, "Total compile time %.4f milliseconds\n",
+ (((double)total_compile_time * 1000.0) / (double)timeit) /
+ (double)CLOCKS_PER_SEC);
+ if (total_jit_compile_time > 0)
+ fprintf(outfile, "Total JIT compile %.4f milliseconds\n",
+ (((double)total_jit_compile_time * 1000.0) / (double)timeit) /
+ (double)CLOCKS_PER_SEC);
+ pad = " ";
+ }
+ fprintf(outfile, "Total match time %s%.4f milliseconds\n", pad,
+ (((double)total_match_time * 1000.0) / (double)timeitm) /
+ (double)CLOCKS_PER_SEC);
+ }
+
+
+EXIT:
+
+#if defined(SUPPORT_LIBREADLINE) || defined(SUPPORT_LIBEDIT)
+if (infile != NULL && INTERACTIVE(infile)) clear_history();
+#endif
+
+if (infile != NULL && infile != stdin) fclose(infile);
+if (outfile != NULL && outfile != stdout) fclose(outfile);
+
+free(buffer);
+free(dbuffer);
+free(pbuffer8);
+free(dfa_workspace);
+free((void *)locale_tables);
+PCRE2_MATCH_DATA_FREE(match_data);
+SUB1(pcre2_code_free, compiled_code);
+
+while(patstacknext-- > 0)
+ {
+ SET(compiled_code, patstack[patstacknext]);
+ SUB1(pcre2_code_free, compiled_code);
+ }
+
+PCRE2_JIT_FREE_UNUSED_MEMORY(general_context);
+if (jit_stack != NULL)
+ {
+ PCRE2_JIT_STACK_FREE(jit_stack);
+ }
+
+#define FREECONTEXTS \
+ G(pcre2_general_context_free_,BITS)(G(general_context,BITS)); \
+ G(pcre2_general_context_free_,BITS)(G(general_context_copy,BITS)); \
+ G(pcre2_compile_context_free_,BITS)(G(pat_context,BITS)); \
+ G(pcre2_compile_context_free_,BITS)(G(default_pat_context,BITS)); \
+ G(pcre2_match_context_free_,BITS)(G(dat_context,BITS)); \
+ G(pcre2_match_context_free_,BITS)(G(default_dat_context,BITS)); \
+ G(pcre2_convert_context_free_,BITS)(G(default_con_context,BITS)); \
+ G(pcre2_convert_context_free_,BITS)(G(con_context,BITS));
+
+#ifdef SUPPORT_PCRE2_8
+#undef BITS
+#define BITS 8
+if (preg.re_pcre2_code != NULL) regfree(&preg);
+FREECONTEXTS;
+#endif
+
+#ifdef SUPPORT_PCRE2_16
+#undef BITS
+#define BITS 16
+free(pbuffer16);
+FREECONTEXTS;
+#endif
+
+#ifdef SUPPORT_PCRE2_32
+#undef BITS
+#define BITS 32
+free(pbuffer32);
+FREECONTEXTS;
+#endif
+
+#if defined(__VMS)
+ yield = SS$_NORMAL; /* Return values via DCL symbols */
+#endif
+
+return yield;
+}
+
+/* End of pcre2test.c */